summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ApiDocs.bp4
-rw-r--r--StubLibraries.bp2
-rw-r--r--apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java3
-rw-r--r--apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java2
-rw-r--r--apex/media/OWNERS3
-rw-r--r--api/current.txt58
-rw-r--r--api/module-lib-current.txt4
-rw-r--r--api/test-current.txt8
-rw-r--r--cmds/statsd/src/atoms.proto56
-rw-r--r--core/java/android/app/ActivityManager.java15
-rw-r--r--core/java/android/app/IActivityManager.aidl6
-rw-r--r--core/java/android/app/PendingIntent.java53
-rw-r--r--core/java/android/app/people/IPeopleManager.aidl6
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl2
-rw-r--r--core/java/android/content/pm/PackageManager.java15
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java16
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java16
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java10
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintSensorProperties.java2
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl4
-rw-r--r--core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl6
-rw-r--r--core/java/android/net/LinkProperties.java5
-rw-r--r--core/java/android/net/MacAddress.java2
-rw-r--r--core/java/android/net/RouteInfo.java3
-rw-r--r--core/java/android/os/BatteryStats.java12
-rw-r--r--core/java/android/os/GraphicsEnvironment.java1
-rw-r--r--core/java/android/os/IPowerManager.aidl2
-rw-r--r--core/java/android/os/PowerManager.java21
-rw-r--r--core/java/android/provider/Settings.java9
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java4
-rw-r--r--core/java/android/util/Log.java2
-rw-r--r--core/java/android/util/imetracing/ImeTracing.java114
-rw-r--r--core/java/android/util/imetracing/ImeTracingClientImpl.java71
-rw-r--r--core/java/android/util/imetracing/ImeTracingServerImpl.java154
-rw-r--r--core/java/android/view/IWindow.aidl6
-rw-r--r--core/java/android/view/IWindowManager.aidl11
-rw-r--r--core/java/android/view/IWindowSession.aidl9
-rw-r--r--core/java/android/view/ImeFocusController.java15
-rw-r--r--core/java/android/view/ImeInsetsSourceConsumer.java16
-rw-r--r--core/java/android/view/InsetsAnimationControlImpl.java29
-rw-r--r--core/java/android/view/InsetsAnimationControlRunner.java11
-rw-r--r--core/java/android/view/InsetsAnimationThreadControlRunner.java7
-rw-r--r--core/java/android/view/InsetsController.java35
-rw-r--r--core/java/android/view/InsetsFlags.java47
-rw-r--r--core/java/android/view/InsetsSource.java16
-rw-r--r--core/java/android/view/InsetsSourceConsumer.java29
-rw-r--r--core/java/android/view/InsetsSourceControl.java22
-rw-r--r--core/java/android/view/InsetsState.java13
-rw-r--r--core/java/android/view/OnReceiveContentCallback.java377
-rw-r--r--core/java/android/view/View.java150
-rw-r--r--core/java/android/view/ViewRootImpl.java89
-rw-r--r--core/java/android/view/WindowManager.java11
-rw-r--r--core/java/android/view/WindowManagerImpl.java9
-rw-r--r--core/java/android/view/WindowlessWindowManager.java10
-rw-r--r--core/java/android/view/inputmethod/BaseInputConnection.java40
-rw-r--r--core/java/android/view/inputmethod/EditorInfo.java27
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java95
-rw-r--r--core/java/android/widget/Editor.java11
-rw-r--r--core/java/android/widget/RichContentReceiver.java234
-rw-r--r--core/java/android/widget/TextView.java144
-rw-r--r--core/java/android/widget/TextViewOnReceiveContentCallback.java (renamed from core/java/android/widget/TextViewRichContentReceiver.java)62
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java2
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java183
-rw-r--r--core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java259
-rw-r--r--core/java/com/android/internal/os/SystemServerCpuThreadReader.java92
-rw-r--r--core/java/com/android/internal/os/SystemServicePowerCalculator.java42
-rw-r--r--core/java/com/android/internal/view/BaseIWindow.java7
-rw-r--r--core/java/com/android/internal/view/IInputMethodClient.aidl1
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl2
-rw-r--r--core/java/com/android/internal/widget/EditableInputConnection.java27
-rw-r--r--core/jni/core_jni_helpers.h6
-rw-r--r--core/proto/OWNERS3
-rw-r--r--core/proto/android/server/peopleservice.proto9
-rw-r--r--core/proto/android/telephony/enums.proto47
-rw-r--r--core/proto/android/view/imeinsetssourceconsumer.proto6
-rw-r--r--core/proto/android/view/inputmethod/inputmethodeditortrace.proto16
-rw-r--r--core/res/AndroidManifest.xml4
-rw-r--r--core/tests/coretests/AndroidManifest.xml1
-rw-r--r--core/tests/coretests/src/android/app/activity/ActivityThreadTest.java8
-rw-r--r--core/tests/coretests/src/android/view/InsetsFlagsTest.java72
-rw-r--r--core/tests/coretests/src/android/widget/TextViewProcessTextTest.java116
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java152
-rw-r--r--core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java89
-rw-r--r--core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java27
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java69
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java28
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java20
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java93
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java86
-rw-r--r--libs/androidfw/include/androidfw/CursorWindow.h2
-rw-r--r--media/java/android/media/MediaMetadata.java94
-rw-r--r--media/java/android/media/Ringtone.java2
-rw-r--r--media/java/android/media/RingtoneManager.java15
-rw-r--r--media/java/android/media/session/MediaSession.java4
-rw-r--r--non-updatable-api/current.txt58
-rw-r--r--non-updatable-api/module-lib-current.txt4
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_settings_icon.xml26
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_user_icon.xml2
-rw-r--r--packages/CarSystemUI/res/layout/car_top_navigation_bar.xml4
-rw-r--r--packages/CarSystemUI/res/layout/system_icons.xml12
-rw-r--r--packages/CarSystemUI/res/values/colors.xml2
-rw-r--r--packages/CarSystemUI/res/values/dimens.xml4
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java4
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/Shell/src/com/android/shell/BugreportProgressService.java4
-rw-r--r--packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java13
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/emergency/EmergencyGesture.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Recents.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/TvNotificationPanel.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java46
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java3
-rw-r--r--packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java3
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/Tethering.java2
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java4
-rw-r--r--services/core/java/com/android/server/NsdService.java2
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java14
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java4
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java4
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java263
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java114
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java98
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java18
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java10
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java6
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java6
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/UdfpsHelper.java10
-rw-r--r--services/core/java/com/android/server/connectivity/VpnIkev2Utils.java2
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java15
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java6
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java70
-rw-r--r--services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java11
-rw-r--r--services/core/java/com/android/server/media/MediaShellCommand.java16
-rw-r--r--services/core/java/com/android/server/media/VolumeCtrl.java28
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java9
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java9
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java25
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java16
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java10
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java54
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java55
-rw-r--r--services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java3
-rw-r--r--services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java20
-rw-r--r--services/core/java/com/android/server/wm/PolicyControl.java270
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java72
-rw-r--r--services/core/java/com/android/server/wm/Session.java16
-rw-r--r--services/core/java/com/android/server/wm/Task.java8
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java6
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotSurface.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java63
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java172
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java17
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp31
-rw-r--r--services/people/java/com/android/server/people/PeopleService.java36
-rw-r--r--services/people/java/com/android/server/people/data/ConversationInfo.java73
-rw-r--r--services/people/java/com/android/server/people/data/DataManager.java224
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java4
-rw-r--r--services/tests/servicestests/AndroidManifest.xml1
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java28
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java26
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java47
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java16
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java299
-rw-r--r--services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java70
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java29
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestIWindow.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java63
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java4
-rwxr-xr-xtelephony/java/android/telephony/CarrierConfigManager.java39
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java6
-rw-r--r--tests/net/common/java/android/net/LinkPropertiesTest.java2
-rw-r--r--tests/net/java/android/net/MacAddressTest.java4
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java2
-rw-r--r--wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java3
-rw-r--r--wifi/java/android/net/wifi/util/SdkLevelUtil.java14
-rw-r--r--wifi/tests/src/android/net/wifi/WifiConfigurationTest.java3
199 files changed, 4733 insertions, 2235 deletions
diff --git a/ApiDocs.bp b/ApiDocs.bp
index c82fee0fe8ac..faa0e5dba997 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -65,7 +65,7 @@ stubs_defaults {
"test-base/src/**/*.java",
":opt-telephony-srcs",
":opt-net-voip-srcs",
- ":art-module-public-api-stubs-source",
+ ":art.module.public.api{.public.stubs.source}",
":conscrypt.module.public.api{.public.stubs.source}",
":android_icu4j_public_api_files",
"test-mock/src/**/*.java",
@@ -135,7 +135,7 @@ doc_defaults {
],
knowntags: [
"docs/knowntags.txt",
- ":known-oj-tags",
+ ":art.module.public.api{.doctags}",
],
custom_template: "droiddoc-templates-sdk",
resourcesdir: "docs/html/reference/images/",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 852fcc6128c4..a3a209458679 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -47,7 +47,7 @@ stubs_defaults {
"core/java/**/*.logtags",
":opt-telephony-srcs",
":opt-net-voip-srcs",
- ":art-module-public-api-stubs-source",
+ ":art.module.public.api{.public.stubs.source}",
":android_icu4j_public_api_files",
"**/package.html",
],
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
index a701f8631969..ecd149989ce6 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
@@ -139,7 +139,6 @@ public class RelayoutPerfTest extends WindowManagerPerfTestBase
final IntSupplier mViewVisibility;
- int mSeq;
int mFrameNumber;
int mFlags;
@@ -156,7 +155,7 @@ public class RelayoutPerfTest extends WindowManagerPerfTestBase
void runBenchmark(BenchmarkState state) throws RemoteException {
final IWindowSession session = WindowManagerGlobal.getWindowSession();
while (state.keepRunning()) {
- session.relayout(mWindow, mSeq, mParams, mWidth, mHeight,
+ session.relayout(mWindow, mParams, mWidth, mHeight,
mViewVisibility.getAsInt(), mFlags, mFrameNumber, mOutFrames,
mOutMergedConfiguration, mOutSurfaceControl, mOutInsetsState, mOutControls,
mOutSurfaceSize, mOutBlastSurfaceControl);
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
index c52b1300aedc..b11d74646d67 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java
@@ -107,7 +107,7 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase
final InputChannel inputChannel = new InputChannel();
long startTime = SystemClock.elapsedRealtimeNanos();
- session.addToDisplay(this, mSeq, mLayoutParams, View.VISIBLE,
+ session.addToDisplay(this, mLayoutParams, View.VISIBLE,
Display.DEFAULT_DISPLAY, mOutFrame, mOutContentInsets, mOutStableInsets,
mOutDisplayCutout, inputChannel, mOutInsetsState, mOutControls);
final long elapsedTimeNsOfAdd = SystemClock.elapsedRealtimeNanos() - startTime;
diff --git a/apex/media/OWNERS b/apex/media/OWNERS
index e83ea3a5087a..ced2fb5e2dcd 100644
--- a/apex/media/OWNERS
+++ b/apex/media/OWNERS
@@ -1,7 +1,10 @@
andrewlewis@google.com
aquilescanta@google.com
chz@google.com
+hdmoon@google.com
hkuang@google.com
+jinpark@google.com
+klhyun@google.com
lnilsson@google.com
marcone@google.com
sungsoo@google.com
diff --git a/api/current.txt b/api/current.txt
index b93ffe3bc745..2c2a5a879417 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6138,6 +6138,7 @@ package android.app {
field @NonNull public static final android.os.Parcelable.Creator<android.app.PendingIntent> CREATOR;
field public static final int FLAG_CANCEL_CURRENT = 268435456; // 0x10000000
field public static final int FLAG_IMMUTABLE = 67108864; // 0x4000000
+ field public static final int FLAG_MUTABLE = 33554432; // 0x2000000
field public static final int FLAG_NO_CREATE = 536870912; // 0x20000000
field public static final int FLAG_ONE_SHOT = 1073741824; // 0x40000000
field public static final int FLAG_UPDATE_CURRENT = 134217728; // 0x8000000
@@ -26359,6 +26360,7 @@ package android.media {
method public boolean containsKey(String);
method public int describeContents();
method public android.graphics.Bitmap getBitmap(String);
+ method @IntRange(from=0) public int getBitmapDimensionLimit();
method @NonNull public android.media.MediaDescription getDescription();
method public long getLong(String);
method public android.media.Rating getRating(String);
@@ -26408,6 +26410,7 @@ package android.media {
method public android.media.MediaMetadata.Builder putRating(String, android.media.Rating);
method public android.media.MediaMetadata.Builder putString(String, String);
method public android.media.MediaMetadata.Builder putText(String, CharSequence);
+ method @NonNull public android.media.MediaMetadata.Builder setBitmapDimensionLimit(int);
}
@Deprecated public abstract class MediaMetadataEditor {
@@ -46797,6 +46800,7 @@ package android.telephony {
field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
field public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL = "carrier_supports_ss_over_ut_bool";
field public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
+ field public static final String KEY_CARRIER_USSD_METHOD_INT = "carrier_ussd_method_int";
field public static final String KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL = "carrier_ut_provisioning_required_bool";
field public static final String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
field public static final String KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL = "carrier_volte_override_wfc_provisioning_bool";
@@ -46991,6 +46995,10 @@ package android.telephony {
field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
field public static final int SERVICE_CLASS_NONE = 0; // 0x0
field public static final int SERVICE_CLASS_VOICE = 1; // 0x1
+ field public static final int USSD_OVER_CS_ONLY = 2; // 0x2
+ field public static final int USSD_OVER_CS_PREFERRED = 0; // 0x0
+ field public static final int USSD_OVER_IMS_ONLY = 3; // 0x3
+ field public static final int USSD_OVER_IMS_PREFERRED = 1; // 0x1
}
public static final class CarrierConfigManager.Apn {
@@ -53644,6 +53652,33 @@ package android.view {
field public int toolType;
}
+ public interface OnReceiveContentCallback<T extends android.view.View> {
+ method @NonNull public java.util.Set<java.lang.String> getSupportedMimeTypes(@NonNull T);
+ method public boolean onReceiveContent(@NonNull T, @NonNull android.view.OnReceiveContentCallback.Payload);
+ }
+
+ public static final class OnReceiveContentCallback.Payload {
+ method @NonNull public android.content.ClipData getClip();
+ method @Nullable public android.os.Bundle getExtras();
+ method public int getFlags();
+ method @Nullable public android.net.Uri getLinkUri();
+ method public int getSource();
+ field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
+ field public static final int SOURCE_AUTOFILL = 3; // 0x3
+ field public static final int SOURCE_CLIPBOARD = 0; // 0x0
+ field public static final int SOURCE_DRAG_AND_DROP = 2; // 0x2
+ field public static final int SOURCE_INPUT_METHOD = 1; // 0x1
+ field public static final int SOURCE_PROCESS_TEXT = 4; // 0x4
+ }
+
+ public static final class OnReceiveContentCallback.Payload.Builder {
+ ctor public OnReceiveContentCallback.Payload.Builder(@NonNull android.content.ClipData, int);
+ method @NonNull public android.view.OnReceiveContentCallback.Payload build();
+ method @NonNull public android.view.OnReceiveContentCallback.Payload.Builder setExtras(@Nullable android.os.Bundle);
+ method @NonNull public android.view.OnReceiveContentCallback.Payload.Builder setFlags(int);
+ method @NonNull public android.view.OnReceiveContentCallback.Payload.Builder setLinkUri(@Nullable android.net.Uri);
+ }
+
public abstract class OrientationEventListener {
ctor public OrientationEventListener(android.content.Context);
ctor public OrientationEventListener(android.content.Context, int);
@@ -54195,6 +54230,7 @@ package android.view {
method @IdRes public int getNextFocusRightId();
method @IdRes public int getNextFocusUpId();
method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
+ method @Nullable public android.view.OnReceiveContentCallback<? extends android.view.View> getOnReceiveContentCallback();
method @ColorInt public int getOutlineAmbientShadowColor();
method public android.view.ViewOutlineProvider getOutlineProvider();
method @ColorInt public int getOutlineSpotShadowColor();
@@ -54546,6 +54582,7 @@ package android.view {
method public void setOnHoverListener(android.view.View.OnHoverListener);
method public void setOnKeyListener(android.view.View.OnKeyListener);
method public void setOnLongClickListener(@Nullable android.view.View.OnLongClickListener);
+ method public void setOnReceiveContentCallback(@Nullable android.view.OnReceiveContentCallback<? extends android.view.View>);
method public void setOnScrollChangeListener(android.view.View.OnScrollChangeListener);
method @Deprecated public void setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener);
method public void setOnTouchListener(android.view.View.OnTouchListener);
@@ -60808,17 +60845,6 @@ package android.widget {
method public android.view.View newGroupView(android.content.Context, android.database.Cursor, boolean, android.view.ViewGroup);
}
- public interface RichContentReceiver<T extends android.view.View> {
- method @NonNull public java.util.Set<java.lang.String> getSupportedMimeTypes();
- method public boolean onReceive(@NonNull T, @NonNull android.content.ClipData, int, int);
- field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
- field public static final int SOURCE_AUTOFILL = 3; // 0x3
- field public static final int SOURCE_CLIPBOARD = 0; // 0x0
- field public static final int SOURCE_DRAG_AND_DROP = 2; // 0x2
- field public static final int SOURCE_INPUT_METHOD = 1; // 0x1
- field public static final int SOURCE_PROCESS_TEXT = 4; // 0x4
- }
-
public class ScrollView extends android.widget.FrameLayout {
ctor public ScrollView(android.content.Context);
ctor public ScrollView(android.content.Context, android.util.AttributeSet);
@@ -61373,10 +61399,10 @@ package android.widget {
method public int getMinWidth();
method public final android.text.method.MovementMethod getMovementMethod();
method public int getOffsetForPosition(float, float);
+ method @Nullable public android.view.OnReceiveContentCallback<android.widget.TextView> getOnReceiveContentCallback();
method public android.text.TextPaint getPaint();
method public int getPaintFlags();
method public String getPrivateImeOptions();
- method @NonNull public android.widget.RichContentReceiver<android.widget.TextView> getRichContentReceiver();
method public int getSelectionEnd();
method public int getSelectionStart();
method @ColorInt public int getShadowColor();
@@ -61504,7 +61530,6 @@ package android.widget {
method public void setPaintFlags(int);
method public void setPrivateImeOptions(String);
method public void setRawInputType(int);
- method public void setRichContentReceiver(@NonNull android.widget.RichContentReceiver<android.widget.TextView>);
method public void setScroller(android.widget.Scroller);
method public void setSelectAllOnFocus(boolean);
method public void setShadowLayer(float, float, float, int);
@@ -61545,7 +61570,6 @@ package android.widget {
method public void setWidth(int);
field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0
field public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1; // 0x1
- field @NonNull public static final android.widget.RichContentReceiver<android.widget.TextView> DEFAULT_RICH_CONTENT_RECEIVER;
}
public enum TextView.BufferType {
@@ -61562,6 +61586,12 @@ package android.widget {
field @NonNull public static final android.os.Parcelable.Creator<android.widget.TextView.SavedState> CREATOR;
}
+ public class TextViewOnReceiveContentCallback implements android.view.OnReceiveContentCallback<android.widget.TextView> {
+ ctor public TextViewOnReceiveContentCallback();
+ method @NonNull public java.util.Set<java.lang.String> getSupportedMimeTypes(@NonNull android.widget.TextView);
+ method public boolean onReceiveContent(@NonNull android.widget.TextView, @NonNull android.view.OnReceiveContentCallback.Payload);
+ }
+
public interface ThemedSpinnerAdapter extends android.widget.SpinnerAdapter {
method @Nullable public android.content.res.Resources.Theme getDropDownViewTheme();
method public void setDropDownViewTheme(@Nullable android.content.res.Resources.Theme);
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index eb2f26448a69..4a7c1210267e 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -53,10 +53,6 @@ package android.media {
field public static final int FLAG_FROM_KEY = 4096; // 0x1000
}
- public static final class MediaMetadata.Builder {
- ctor public MediaMetadata.Builder(@NonNull android.media.MediaMetadata, @IntRange(from=1) int);
- }
-
public final class MediaParceledListSlice<T extends android.os.Parcelable> implements android.os.Parcelable {
ctor public MediaParceledListSlice(@NonNull java.util.List<T>);
method public int describeContents();
diff --git a/api/test-current.txt b/api/test-current.txt
index 3a4d101ddfa3..8e437f14eeb8 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -83,6 +83,7 @@ package android.app {
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getPackageImportance(String);
method public long getTotalRam();
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getUidImportance(int);
+ method @RequiresPermission("android.permission.INJECT_EVENTS") public void holdLock(int);
method public static boolean isHighEndGfx();
method @RequiresPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) public void killProcessesWhenImperceptible(@NonNull int[], @NonNull String);
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
@@ -1023,6 +1024,7 @@ package android.content.pm {
method @Nullable public String getSystemTextClassifierPackageName();
method @Nullable public String getWellbeingPackageName();
method @RequiresPermission("android.permission.GRANT_RUNTIME_PERMISSIONS") public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
+ method @RequiresPermission("android.permission.INJECT_EVENTS") public void holdLock(int);
method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void removeOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener);
method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull String);
@@ -5289,6 +5291,7 @@ package android.view {
}
public interface WindowManager extends android.view.ViewManager {
+ method @RequiresPermission("android.permission.INJECT_EVENTS") public default void holdLock(int);
method public default void setShouldShowIme(int, boolean);
method public default void setShouldShowSystemDecors(int, boolean);
method public default void setShouldShowWithInsecureKeyguard(int, boolean);
@@ -5581,6 +5584,11 @@ package android.widget {
method public void disableClockTick();
}
+ @android.widget.RemoteViews.RemoteView public class TextView extends android.view.View implements android.view.ViewTreeObserver.OnPreDrawListener {
+ method public void onActivityResult(int, int, @Nullable android.content.Intent);
+ field public static final int PROCESS_TEXT_REQUEST_CODE = 100; // 0x64
+ }
+
public class TimePicker extends android.widget.FrameLayout {
method public android.view.View getAmView();
method public android.view.View getHourView();
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 4ccc7e64308a..c327d1a14257 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -499,7 +499,7 @@ message Atom {
}
// Pulled events will start at field 10000.
- // Next: 10084
+ // Next: 10087
oneof pulled {
WifiBytesTransfer wifi_bytes_transfer = 10000 [(module) = "framework"];
WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001 [(module) = "framework"];
@@ -598,6 +598,7 @@ message Atom {
DNDModeProto dnd_mode_rule = 10084 [(module) = "framework"];
GeneralExternalStorageAccessStats general_external_storage_access_stats =
10085 [(module) = "mediaprovider"];
+ IncomingSms incoming_sms = 10086 [(module) = "telephony"];
}
// DO NOT USE field numbers above 100,000 in AOSP.
@@ -10461,6 +10462,59 @@ message SupportedRadioAccessFamily {
}
/**
+ * Pulls information for a single incoming SMS.
+ *
+ * Each pull creates multiple atoms, one for each SMS. The sequence is randomized when pulled.
+ *
+ * Pulled from:
+ * frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
+ */
+message IncomingSms {
+ // Format of the SMS (3GPP or 3GPP2).
+ optional android.telephony.SmsFormatEnum sms_format = 1;
+
+ // Technology of the SMS (CS or IMS).
+ optional android.telephony.SmsTechEnum sms_tech = 2;
+
+ // Radio access technology (RAT) used for the SMS. It can be IWLAN in case of IMS.
+ optional android.telephony.NetworkTypeEnum rat = 3;
+
+ // Type the SMS.
+ optional android.telephony.SmsTypeEnum sms_type = 4;
+
+ // Number of total parts.
+ optional int32 total_parts = 5;
+
+ // Number of received parts (if smaller than total parts, the SMS was dropped).
+ optional int32 received_parts = 6;
+
+ // Indicates if the incoming SMS was blocked.
+ optional bool blocked = 7;
+
+ // Indicate a specific error handling the SMS
+ optional android.telephony.SmsIncomingErrorEnum error = 8;
+
+ // Whether the SMS was received while roaming.
+ optional bool is_roaming = 9;
+
+ // Index of the SIM is used, 0 for single-SIM devices.
+ optional int32 sim_slot_index = 10;
+
+ // Whether the device was in multi-SIM mode (with multiple active SIM profiles).
+ optional bool is_multi_sim = 11;
+
+ // Whether the message was received with an eSIM profile.
+ optional bool is_esim = 12;
+
+ // Carrier ID of the SIM card used for the SMS.
+ // See https://source.android.com/devices/tech/config/carrierid.
+ optional int32 carrier_id = 13;
+
+ // Random message ID.
+ optional int64 message_id = 14;
+}
+
+/**
* Logs gnss stats from location service provider
*
* Pulled from:
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 70ca49d67930..e75d2f60bb87 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4796,4 +4796,19 @@ public class ActivityManager {
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Holds the AM lock for the specified amount of milliseconds.
+ * This is intended for use by the tests that need to imitate lock contention.
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.INJECT_EVENTS)
+ public void holdLock(int durationMs) {
+ try {
+ getService().holdLock(durationMs);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 95bbebecd66e..1a4db4e541cc 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -696,4 +696,10 @@ interface IActivityManager {
* @param enable set it to true to enable the app freezer, false to disable it.
*/
boolean enableAppFreezer(in boolean enable);
+
+ /**
+ * Holds the AM lock for the specified amount of milliseconds.
+ * This is intended for use by the tests that need to imitate lock contention.
+ */
+ void holdLock(in int durationMs);
}
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index cd352e141994..8e3ee0cbceff 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -19,12 +19,16 @@ package android.app;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -35,6 +39,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.util.AndroidException;
import android.util.ArraySet;
+import android.util.Log;
import android.util.proto.ProtoOutputStream;
import com.android.internal.os.IResultReceiver;
@@ -102,11 +107,20 @@ import java.lang.annotation.RetentionPolicy;
* FLAG_ONE_SHOT, <b>both</b> FLAG_ONE_SHOT and FLAG_NO_CREATE need to be supplied.
*/
public final class PendingIntent implements Parcelable {
+ private static final String TAG = "PendingIntent";
private final IIntentSender mTarget;
private IResultReceiver mCancelReceiver;
private IBinder mWhitelistToken;
private ArraySet<CancelListener> mCancelListeners;
+ /**
+ * It is now required to specify either {@link #FLAG_IMMUTABLE}
+ * or {@link #FLAG_MUTABLE} when creating a PendingIntent.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.R)
+ static final long PENDING_INTENT_EXPLICIT_MUTABILITY_REQUIRED = 160794467L;
+
/** @hide */
@IntDef(flag = true,
value = {
@@ -115,6 +129,7 @@ public final class PendingIntent implements Parcelable {
FLAG_CANCEL_CURRENT,
FLAG_UPDATE_CURRENT,
FLAG_IMMUTABLE,
+ FLAG_MUTABLE,
Intent.FILL_IN_ACTION,
Intent.FILL_IN_DATA,
@@ -175,6 +190,20 @@ public final class PendingIntent implements Parcelable {
public static final int FLAG_IMMUTABLE = 1<<26;
/**
+ * Flag indicating that the created PendingIntent should be mutable.
+ * This flag cannot be combined with {@link #FLAG_IMMUTABLE}. <p>Up until
+ * {@link android.os.Build.VERSION_CODES#R}, PendingIntents are assumed to
+ * be mutable by default, unless {@link #FLAG_IMMUTABLE} is set. Starting
+ * with {@link android.os.Build.VERSION_CODES#S}, it will be required to
+ * explicitly specify the mutability of PendingIntents on creation with
+ * either (@link #FLAG_IMMUTABLE} or {@link #FLAG_MUTABLE}. It is strongly
+ * recommended to use {@link #FLAG_IMMUTABLE} when creating a
+ * PendingIntent. {@link #FLAG_MUTABLE} should only be used when some
+ * functionality relies on modifying the underlying intent.
+ */
+ public static final int FLAG_MUTABLE = 1<<25;
+
+ /**
* Exception thrown when trying to send through a PendingIntent that
* has been canceled or is otherwise no longer able to execute the request.
*/
@@ -286,6 +315,24 @@ public final class PendingIntent implements Parcelable {
sOnMarshaledListener.set(listener);
}
+ private static void checkFlags(int flags, String packageName) {
+ final boolean flagImmutableSet = (flags & PendingIntent.FLAG_IMMUTABLE) != 0;
+ final boolean flagMutableSet = (flags & PendingIntent.FLAG_MUTABLE) != 0;
+ String msg = packageName + ": Targeting S+ (version " + Build.VERSION_CODES.S
+ + " and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE"
+ + " be specified when creating a PendingIntent";
+
+ if (flagImmutableSet && flagMutableSet) {
+ throw new IllegalArgumentException(
+ "Cannot set both FLAG_IMMUTABLE and FLAG_MUTABLE for PendingIntent");
+ }
+
+ if (Compatibility.isChangeEnabled(PENDING_INTENT_EXPLICIT_MUTABILITY_REQUIRED)
+ && !flagImmutableSet && !flagMutableSet) {
+ Log.e(TAG, msg);
+ }
+ }
+
/**
* Retrieve a PendingIntent that will start a new activity, like calling
* {@link Context#startActivity(Intent) Context.startActivity(Intent)}.
@@ -350,6 +397,7 @@ public final class PendingIntent implements Parcelable {
String packageName = context.getPackageName();
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
+ checkFlags(flags, packageName);
try {
intent.migrateExtraStreamToClipData(context);
intent.prepareToLeaveProcess(context);
@@ -376,6 +424,7 @@ public final class PendingIntent implements Parcelable {
String packageName = context.getPackageName();
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
+ checkFlags(flags, packageName);
try {
intent.migrateExtraStreamToClipData(context);
intent.prepareToLeaveProcess(context);
@@ -495,6 +544,7 @@ public final class PendingIntent implements Parcelable {
intents[i].prepareToLeaveProcess(context);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
}
+ checkFlags(flags, packageName);
try {
IIntentSender target =
ActivityManager.getService().getIntentSenderWithFeature(
@@ -521,6 +571,7 @@ public final class PendingIntent implements Parcelable {
intents[i].prepareToLeaveProcess(context);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
}
+ checkFlags(flags, packageName);
try {
IIntentSender target =
ActivityManager.getService().getIntentSenderWithFeature(
@@ -572,6 +623,7 @@ public final class PendingIntent implements Parcelable {
String packageName = context.getPackageName();
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
+ checkFlags(flags, packageName);
try {
intent.prepareToLeaveProcess(context);
IIntentSender target =
@@ -651,6 +703,7 @@ public final class PendingIntent implements Parcelable {
String packageName = context.getPackageName();
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
+ checkFlags(flags, packageName);
try {
intent.prepareToLeaveProcess(context);
IIntentSender target =
diff --git a/core/java/android/app/people/IPeopleManager.aidl b/core/java/android/app/people/IPeopleManager.aidl
index 61dac0d64422..c547ef1e7e9b 100644
--- a/core/java/android/app/people/IPeopleManager.aidl
+++ b/core/java/android/app/people/IPeopleManager.aidl
@@ -39,4 +39,10 @@ interface IPeopleManager {
/** Removes all the recent conversations and uncaches their cached shortcuts. */
void removeAllRecentConversations();
+
+ /**
+ * Returns the last interaction with the specified conversation. If the
+ * conversation can't be found or no interactions have been recorded, returns 0L.
+ */
+ long getLastInteraction(in String packageName, int userId, in String shortcutId);
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 24282365a8c7..ba894ae72017 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -795,4 +795,6 @@ interface IPackageManager {
boolean isAutoRevokeWhitelisted(String packageName);
void grantImplicitAccess(int queryingUid, String visibleAuthority);
+
+ void holdLock(in int durationMs);
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 4eec56c0d87b..79e23b37be05 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -8305,4 +8305,19 @@ public abstract class PackageManager {
public static void uncorkPackageInfoCache() {
PropertyInvalidatedCache.uncorkInvalidations(PermissionManager.CACHE_KEY_PACKAGE_INFO);
}
+
+ /**
+ * Holds the PM lock for the specified amount of milliseconds.
+ * Intended for use by the tests that need to imitate lock contention.
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.INJECT_EVENTS)
+ public void holdLock(int durationMs) {
+ try {
+ ActivityThread.getPackageManager().holdLock(durationMs);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 1061121b4449..0d0bfb32e293 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2175,10 +2175,8 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
/**
* <p>The desired zoom ratio</p>
- * <p>Instead of using {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} with dual purposes of crop and zoom, the
- * application can now choose to use this tag to specify the desired zoom level. The
- * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} can still be used to specify the horizontal or vertical
- * crop to achieve aspect ratios different than the native camera sensor.</p>
+ * <p>Instead of using {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} for zoom, the application can now choose to
+ * use this tag to specify the desired zoom level.</p>
* <p>By using this control, the application gains a simpler way to control zoom, which can
* be a combination of optical and digital zoom. For example, a multi-camera system may
* contain more than one lens with different focal lengths, and the user can use optical
@@ -2860,11 +2858,18 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* respectively.</p>
* <p>The camera device may adjust the crop region to account for rounding and other hardware
* requirements; the final crop region used will be included in the output capture result.</p>
+ * <p>The camera sensor output aspect ratio depends on factors such as output stream
+ * combination and {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE android.control.aeTargetFpsRange}, and shouldn't be adjusted by using
+ * this control. And the camera device will treat different camera sensor output sizes
+ * (potentially with in-sensor crop) as the same crop of
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}. As a result, the application shouldn't assume the
+ * maximum crop region always maps to the same aspect ratio or field of view for the
+ * sensor output.</p>
* <p>Starting from API level 30, it's strongly recommended to use {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}
* to take advantage of better support for zoom with logical multi-camera. The benefits
* include better precision with optical-digital zoom combination, and ability to do
* zoom-out from 1.0x. When using {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for zoom, the crop region in
- * the capture request must be either letterboxing or pillarboxing (but not both). The
+ * the capture request should be left as the default activeArray size. The
* coordinate system is post-zoom, meaning that the activeArraySize or
* preCorrectionActiveArraySize covers the camera device's field of view "after" zoom. See
* {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for details.</p>
@@ -2874,6 +2879,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* capability and mode</p>
* <p>This key is available on all devices.</p>
*
+ * @see CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE
* @see CaptureRequest#CONTROL_ZOOM_RATIO
* @see CaptureRequest#DISTORTION_CORRECTION_MODE
* @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 29a53fb6d4a2..8cfa0866f13a 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2405,10 +2405,8 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
/**
* <p>The desired zoom ratio</p>
- * <p>Instead of using {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} with dual purposes of crop and zoom, the
- * application can now choose to use this tag to specify the desired zoom level. The
- * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} can still be used to specify the horizontal or vertical
- * crop to achieve aspect ratios different than the native camera sensor.</p>
+ * <p>Instead of using {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} for zoom, the application can now choose to
+ * use this tag to specify the desired zoom level.</p>
* <p>By using this control, the application gains a simpler way to control zoom, which can
* be a combination of optical and digital zoom. For example, a multi-camera system may
* contain more than one lens with different focal lengths, and the user can use optical
@@ -3506,11 +3504,18 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* respectively.</p>
* <p>The camera device may adjust the crop region to account for rounding and other hardware
* requirements; the final crop region used will be included in the output capture result.</p>
+ * <p>The camera sensor output aspect ratio depends on factors such as output stream
+ * combination and {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE android.control.aeTargetFpsRange}, and shouldn't be adjusted by using
+ * this control. And the camera device will treat different camera sensor output sizes
+ * (potentially with in-sensor crop) as the same crop of
+ * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}. As a result, the application shouldn't assume the
+ * maximum crop region always maps to the same aspect ratio or field of view for the
+ * sensor output.</p>
* <p>Starting from API level 30, it's strongly recommended to use {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio}
* to take advantage of better support for zoom with logical multi-camera. The benefits
* include better precision with optical-digital zoom combination, and ability to do
* zoom-out from 1.0x. When using {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for zoom, the crop region in
- * the capture request must be either letterboxing or pillarboxing (but not both). The
+ * the capture request should be left as the default activeArray size. The
* coordinate system is post-zoom, meaning that the activeArraySize or
* preCorrectionActiveArraySize covers the camera device's field of view "after" zoom. See
* {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for details.</p>
@@ -3520,6 +3525,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* capability and mode</p>
* <p>This key is available on all devices.</p>
*
+ * @see CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE
* @see CaptureRequest#CONTROL_ZOOM_RATIO
* @see CaptureRequest#DISTORTION_CORRECTION_MODE
* @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index c12bb39c3175..997efbedb0de 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -746,7 +746,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public void setUdfpsOverlayController(IUdfpsOverlayController controller) {
+ public void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller) {
if (mService == null) {
Slog.w(TAG, "setUdfpsOverlayController: no fingerprint service");
return;
@@ -763,14 +763,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public void onFingerDown(int x, int y, float minor, float major) {
+ public void onFingerDown(int sensorId, int x, int y, float minor, float major) {
if (mService == null) {
Slog.w(TAG, "onFingerDown: no fingerprint service");
return;
}
try {
- mService.onFingerDown(x, y, minor, major);
+ mService.onFingerDown(sensorId, x, y, minor, major);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
@@ -780,14 +780,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public void onFingerUp() {
+ public void onFingerUp(int sensorId) {
if (mService == null) {
Slog.w(TAG, "onFingerDown: no fingerprint service");
return;
}
try {
- mService.onFingerUp();
+ mService.onFingerUp(sensorId);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java b/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java
index 718141a4845a..d26346c21427 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorProperties.java
@@ -18,9 +18,7 @@ package android.hardware.fingerprint;
import android.annotation.IntDef;
import android.hardware.biometrics.SensorProperties;
-import android.hardware.face.FaceSensorProperties;
import android.os.Parcel;
-import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index cc2b520b3152..68013eae956b 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -121,10 +121,10 @@ interface IFingerprintService {
void initializeConfiguration(int sensorId, int strength);
// Notifies about a finger touching the sensor area.
- void onFingerDown(int x, int y, float minor, float major);
+ void onFingerDown(int sensorId, int x, int y, float minor, float major);
// Notifies about a finger leaving the sensor area.
- void onFingerUp();
+ void onFingerUp(int sensorId);
// Sets the controller for managing the UDFPS overlay.
void setUdfpsOverlayController(in IUdfpsOverlayController controller);
diff --git a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
index a57726c4afe4..58b7046ad991 100644
--- a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
+++ b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
@@ -21,11 +21,11 @@ package android.hardware.fingerprint;
*/
oneway interface IUdfpsOverlayController {
// Shows the overlay.
- void showUdfpsOverlay();
+ void showUdfpsOverlay(int sensorId);
// Hides the overlay.
- void hideUdfpsOverlay();
+ void hideUdfpsOverlay(int sensorId);
// Shows debug messages on the UDFPS overlay.
- void setDebugMessage(String message);
+ void setDebugMessage(int sensorId, String message);
}
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 651494d1c99c..cad103e9f082 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -21,13 +21,14 @@ import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
-import android.net.util.LinkPropertiesUtils;
-import android.net.util.LinkPropertiesUtils.CompareResult;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import com.android.net.module.util.LinkPropertiesUtils;
+import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
+
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index 0eb3c1e8ad01..51c5a50dcafb 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -20,12 +20,12 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
-import android.net.util.MacAddressUtils;
import android.net.wifi.WifiInfo;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.Preconditions;
+import com.android.net.module.util.MacAddressUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 98760761736d..a8b45e9d128b 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -22,11 +22,12 @@ import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
-import android.net.util.NetUtils;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.net.module.util.NetUtils;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.Inet4Address;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index fdbf79a9f5d2..d889b155cf64 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -21,6 +21,7 @@ import static android.os.BatteryStatsManager.NUM_WIFI_STATES;
import static android.os.BatteryStatsManager.NUM_WIFI_SUPPL_STATES;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.job.JobParameters;
import android.compat.annotation.UnsupportedAppUsage;
@@ -2889,14 +2890,17 @@ public abstract class BatteryStats implements Parcelable {
/**
* Returns the approximate CPU time (in microseconds) spent by the system server handling
- * incoming service calls from apps.
+ * incoming service calls from apps. The result is returned as an array of longs,
+ * organized as a sequence like this:
+ * <pre>
+ * cluster1-speeed1, cluster1-speed2, ..., cluster2-speed1, cluster2-speed2, ...
+ * </pre>
*
- * @param cluster the index of the CPU cluster.
- * @param step the index of the CPU speed. This is not the actual speed of the CPU.
* @see com.android.internal.os.PowerProfile#getNumCpuClusters()
* @see com.android.internal.os.PowerProfile#getNumSpeedStepsInCpuCluster(int)
*/
- public abstract long getSystemServiceTimeAtCpuSpeed(int cluster, int step);
+ @Nullable
+ public abstract long[] getSystemServiceTimeAtCpuSpeeds();
/**
* Returns the total, last, or current battery uptime in microseconds.
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 52ee04c169c1..54f80c613f0a 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -267,6 +267,7 @@ public class GraphicsEnvironment {
}
if (appInfo == null) {
Log.w(TAG, "Debug layer app '" + packageName + "' not installed");
+ return "";
}
final String abi = chooseAbi(appInfo);
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index a92d91bdefc5..e996809f1299 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -98,6 +98,8 @@ interface IPowerManager
boolean isAmbientDisplaySuppressedForToken(String token);
// returns whether ambient display is suppressed by any app with any token.
boolean isAmbientDisplaySuppressed();
+ // returns whether ambient display is suppressed by the given app with the given token.
+ boolean isAmbientDisplaySuppressedForTokenByApp(String token, int appUid);
// Forces the system to suspend even if there are held wakelocks.
boolean forceSuspend();
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 3265829e5061..50f0c28cb8f8 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -2191,6 +2191,27 @@ public final class PowerManager {
}
/**
+ * Returns true if ambient display is suppressed by the given {@code appUid} with the given
+ * {@code token}.
+ *
+ * <p>This method will return false if {@link #isAmbientDisplayAvailable()} is false.
+ *
+ * @param token The identifier of the ambient display suppression.
+ * @param appUid The uid of the app that suppressed ambient display.
+ * @hide
+ */
+ @RequiresPermission(allOf = {
+ android.Manifest.permission.READ_DREAM_STATE,
+ android.Manifest.permission.READ_DREAM_SUPPRESSION })
+ public boolean isAmbientDisplaySuppressedForTokenByApp(@NonNull String token, int appUid) {
+ try {
+ return mService.isAmbientDisplaySuppressedForTokenByApp(token, appUid);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns the reason the phone was last shutdown. Calling app must have the
* {@link android.Manifest.permission#DEVICE_POWER} permission to request this information.
* @return Reason for shutdown as an int, {@link #SHUTDOWN_REASON_UNKNOWN} if the file could
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 07867e2a9d9b..e4d1fabfffd8 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -14464,6 +14464,15 @@ public final class Settings {
*/
public static final String NR_NSA_TRACKING_SCREEN_OFF_MODE =
"nr_nsa_tracking_screen_off_mode";
+
+ /**
+ * Whether to show People Space.
+ * Values are:
+ * 0: Disabled (default)
+ * 1: Enabled
+ * @hide
+ */
+ public static final String SHOW_PEOPLE_SPACE = "show_people_space";
}
/**
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 19860eb45fbf..0f46ffcb2d7f 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -879,7 +879,7 @@ public abstract class WallpaperService extends Service {
com.android.internal.R.style.Animation_Wallpaper;
InputChannel inputChannel = new InputChannel();
- if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE,
+ if (mSession.addToDisplay(mWindow, mLayout, View.VISIBLE,
mDisplay.getDisplayId(), mWinFrames.frame, mWinFrames.contentInsets,
mWinFrames.stableInsets, mWinFrames.displayCutout, inputChannel,
mInsetsState, mTempControls) < 0) {
@@ -903,7 +903,7 @@ public abstract class WallpaperService extends Service {
}
final int relayoutResult = mSession.relayout(
- mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
+ mWindow, mLayout, mWidth, mHeight,
View.VISIBLE, 0, -1, mWinFrames, mMergedConfiguration, mSurfaceControl,
mInsetsState, mTempControls, mSurfaceSize, mTmpSurfaceControl);
if (mSurfaceControl.isValid()) {
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index 2ded473930f7..7a117f14d9b5 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -227,7 +227,7 @@ public final class Log {
* @param level The level to check.
* @return Whether or not that this is allowed to be logged.
* @throws IllegalArgumentException is thrown if the tag.length() > 23
- * for Nougat (7.0) releases (API <= 23) and prior, there is no
+ * for Nougat (7.0) and prior releases (API <= 25), there is no
* tag limit of concern after this API level.
*/
@FastNative
diff --git a/core/java/android/util/imetracing/ImeTracing.java b/core/java/android/util/imetracing/ImeTracing.java
new file mode 100644
index 000000000000..865d5608a40a
--- /dev/null
+++ b/core/java/android/util/imetracing/ImeTracing.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.imetracing;
+
+import android.app.ActivityThread;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceManager.ServiceNotFoundException;
+import android.os.ShellCommand;
+import android.util.Log;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.view.IInputMethodManager;
+
+/**
+ *
+ * An abstract class that declares the methods for ime trace related operations - enable trace,
+ * schedule trace and add new trace to buffer. Both the client and server side classes can use
+ * it by getting an implementation through {@link ImeTracing#getInstance()}.
+ *
+ * @hide
+ */
+public abstract class ImeTracing {
+
+ static final String TAG = "imeTracing";
+ public static final String PROTO_ARG = "--proto-com-android-imetracing";
+
+ private static ImeTracing sInstance;
+ static boolean sEnabled = false;
+ IInputMethodManager mService;
+
+ ImeTracing() throws ServiceNotFoundException {
+ mService = IInputMethodManager.Stub.asInterface(
+ ServiceManager.getServiceOrThrow(Context.INPUT_METHOD_SERVICE));
+ }
+
+ /**
+ * Returns an instance of {@link ImeTracingServerImpl} when called from a server side class
+ * and an instance of {@link ImeTracingClientImpl} when called from a client side class.
+ * Useful to schedule a dump for next frame or save a dump when certain methods are called.
+ *
+ * @return Instance of one of the children classes of {@link ImeTracing}
+ */
+ public static ImeTracing getInstance() {
+ if (sInstance == null) {
+ try {
+ sInstance = isSystemProcess()
+ ? new ImeTracingServerImpl() : new ImeTracingClientImpl();
+ } catch (RemoteException | ServiceNotFoundException e) {
+ Log.e(TAG, "Exception while creating ImeTracing instance", e);
+ }
+ }
+ return sInstance;
+ }
+
+ /**
+ * Sends request to start proto dump to {@link ImeTracingServerImpl} when called from a
+ * server process and to {@link ImeTracingClientImpl} when called from a client process.
+ */
+ public abstract void triggerDump();
+
+ /**
+ * @param proto dump to be added to the buffer
+ */
+ public abstract void addToBuffer(ProtoOutputStream proto);
+
+ /**
+ * @param shell The shell command to process
+ * @return {@code 0} if the command was successfully processed, {@code -1} otherwise
+ */
+ public abstract int onShellCommand(ShellCommand shell);
+
+ /**
+ * Sets whether ime tracing is enabled.
+ *
+ * @param enabled Tells whether ime tracing should be enabled or disabled.
+ */
+ public void setEnabled(boolean enabled) {
+ sEnabled = enabled;
+ }
+
+ /**
+ * @return {@code true} if dumping is enabled, {@code false} otherwise.
+ */
+ public boolean isEnabled() {
+ return sEnabled;
+ }
+
+ /**
+ * @return {@code true} if tracing is available, {@code false} otherwise.
+ */
+ public boolean isAvailable() {
+ return mService != null;
+ }
+
+ private static boolean isSystemProcess() {
+ return ActivityThread.isSystem();
+ }
+}
diff --git a/core/java/android/util/imetracing/ImeTracingClientImpl.java b/core/java/android/util/imetracing/ImeTracingClientImpl.java
new file mode 100644
index 000000000000..e5d7d3380d02
--- /dev/null
+++ b/core/java/android/util/imetracing/ImeTracingClientImpl.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.imetracing;
+
+import android.os.RemoteException;
+import android.os.ServiceManager.ServiceNotFoundException;
+import android.os.ShellCommand;
+import android.util.Log;
+import android.util.proto.ProtoOutputStream;
+import android.view.inputmethod.InputMethodManager;
+
+/**
+ * @hide
+ */
+class ImeTracingClientImpl extends ImeTracing {
+
+ private boolean mDumpInProgress;
+ private final Object mDumpInProgressLock = new Object();
+
+ ImeTracingClientImpl() throws ServiceNotFoundException, RemoteException {
+ sEnabled = mService.isImeTraceEnabled();
+ }
+
+ @Override
+ public void addToBuffer(ProtoOutputStream proto) {
+ }
+
+ @Override
+ public int onShellCommand(ShellCommand shell) {
+ return -1;
+ }
+
+ @Override
+ public void triggerDump() {
+ if (isAvailable() && isEnabled()) {
+ boolean doDump = false;
+ synchronized (mDumpInProgressLock) {
+ if (!mDumpInProgress) {
+ mDumpInProgress = true;
+ doDump = true;
+ }
+ }
+
+ if (doDump) {
+ try {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ InputMethodManager.dumpProto(proto);
+ mService.startProtoDump(proto.getBytes());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception while sending ime-related client dump to server", e);
+ } finally {
+ mDumpInProgress = false;
+ }
+ }
+ }
+ }
+}
diff --git a/core/java/android/util/imetracing/ImeTracingServerImpl.java b/core/java/android/util/imetracing/ImeTracingServerImpl.java
new file mode 100644
index 000000000000..350cf5721148
--- /dev/null
+++ b/core/java/android/util/imetracing/ImeTracingServerImpl.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.imetracing;
+
+import static android.os.Build.IS_USER;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorTraceFileProto.MAGIC_NUMBER;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorTraceFileProto.MAGIC_NUMBER_H;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorTraceFileProto.MAGIC_NUMBER_L;
+
+import android.os.RemoteException;
+import android.os.ServiceManager.ServiceNotFoundException;
+import android.os.ShellCommand;
+import android.util.Log;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.TraceBuffer;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * @hide
+ */
+class ImeTracingServerImpl extends ImeTracing {
+ private static final String TRACE_FILENAME = "/data/misc/wmtrace/ime_trace.pb";
+ private static final int BUFFER_CAPACITY = 4096 * 1024;
+
+ // Needed for winscope to auto-detect the dump type. Explained further in
+ // core.proto.android.view.inputmethod.inputmethodeditortrace.proto
+ private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
+
+ private final TraceBuffer mBuffer;
+ private final File mTraceFile;
+ private final Object mEnabledLock = new Object();
+
+ ImeTracingServerImpl() throws ServiceNotFoundException {
+ mBuffer = new TraceBuffer<>(BUFFER_CAPACITY);
+ mTraceFile = new File(TRACE_FILENAME);
+ }
+
+ /**
+ * The provided dump is added to the current dump buffer {@link ImeTracingServerImpl#mBuffer}.
+ *
+ * @param proto dump to be added to the buffer
+ */
+ @Override
+ public void addToBuffer(ProtoOutputStream proto) {
+ if (isAvailable() && isEnabled()) {
+ mBuffer.add(proto);
+ }
+ }
+
+ /**
+ * Responds to a shell command of the format "adb shell cmd input_method ime tracing <command>"
+ *
+ * @param shell The shell command to process
+ * @return {@code 0} if the command was valid and successfully processed, {@code -1} otherwise
+ */
+ @Override
+ public int onShellCommand(ShellCommand shell) {
+ PrintWriter pw = shell.getOutPrintWriter();
+ String cmd = shell.getNextArgRequired();
+ switch (cmd) {
+ case "start":
+ startTrace(pw);
+ return 0;
+ case "stop":
+ stopTrace(pw);
+ return 0;
+ default:
+ pw.println("Unknown command: " + cmd);
+ pw.println("Input method trace options:");
+ pw.println(" start: Start tracing");
+ pw.println(" stop: Stop tracing");
+ return -1;
+ }
+ }
+
+ @Override
+ public void triggerDump() {
+ if (isAvailable() && isEnabled()) {
+ try {
+ mService.startProtoDump(null);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception while triggering proto dump", e);
+ }
+ }
+ }
+
+ private void writeTraceToFileLocked() {
+ try {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
+ mBuffer.writeTraceToFile(mTraceFile, proto);
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to write buffer to file", e);
+ }
+ }
+
+ @GuardedBy("mEnabledLock")
+ private void startTrace(PrintWriter pw) {
+ if (IS_USER) {
+ Log.w(TAG, "Warn: Tracing is not supported on user builds.");
+ return;
+ }
+
+ synchronized (mEnabledLock) {
+ if (isAvailable() && isEnabled()) {
+ Log.w(TAG, "Warn: Tracing is already started.");
+ return;
+ }
+
+ pw.println("Starting tracing to " + mTraceFile + ".");
+ sEnabled = true;
+ mBuffer.resetBuffer();
+ }
+ }
+
+ @GuardedBy("mEnabledLock")
+ private void stopTrace(PrintWriter pw) {
+ if (IS_USER) {
+ Log.w(TAG, "Warn: Tracing is not supported on user builds.");
+ return;
+ }
+
+ synchronized (mEnabledLock) {
+ if (!isAvailable() || !isEnabled()) {
+ Log.w(TAG, "Warn: Tracing is not available or not started.");
+ return;
+ }
+
+ pw.println("Stopping tracing and writing traces to " + mTraceFile + ".");
+ sEnabled = false;
+ writeTraceToFileLocked();
+ mBuffer.resetBuffer();
+ }
+ }
+}
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 94e641c62b25..193e674dd1b0 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -120,12 +120,6 @@ oneway interface IWindow {
void updatePointerIcon(float x, float y);
/**
- * System chrome visibility changes
- */
- void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
- int localValue, int localChanges);
-
- /**
* Called for non-application windows when the enter animation has completed.
*/
void dispatchWindowShown();
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 8e875d7a889d..daab70ae336f 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -378,11 +378,6 @@ interface IWindowManager
boolean requestAssistScreenshot(IAssistDataReceiver receiver);
/**
- * Called by the status bar to notify Views of changes to System UI visiblity.
- */
- oneway void statusBarVisibilityChanged(int displayId, int visibility);
-
- /**
* Called by System UI to notify Window Manager to hide transient bars.
*/
oneway void hideTransientBars(int displayId);
@@ -757,4 +752,10 @@ interface IWindowManager
*/
void requestScrollCapture(int displayId, IBinder behindClient, int taskId,
IScrollCaptureController controller);
+
+ /**
+ * Holds the WM lock for the specified amount of milliseconds.
+ * Intended for use by the tests that need to imitate lock contention.
+ */
+ void holdLock(in int durationMs);
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 18c87c092569..69a5fafbb0db 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -44,17 +44,17 @@ import java.util.List;
* {@hide}
*/
interface IWindowSession {
- int addToDisplay(IWindow window, int seq, in WindowManager.LayoutParams attrs,
+ int addToDisplay(IWindow window, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, out Rect outFrame,
out Rect outContentInsets, out Rect outStableInsets,
out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel,
out InsetsState insetsState, out InsetsSourceControl[] activeControls);
- int addToDisplayAsUser(IWindow window, int seq, in WindowManager.LayoutParams attrs,
+ int addToDisplayAsUser(IWindow window, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, in int userId,
out Rect outFrame, out Rect outContentInsets, out Rect outStableInsets,
out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel,
out InsetsState insetsState, out InsetsSourceControl[] activeControls);
- int addToDisplayWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs,
+ int addToDisplayWithoutInputChannel(IWindow window, in WindowManager.LayoutParams attrs,
in int viewVisibility, in int layerStackId, out Rect outContentInsets,
out Rect outStableInsets, out InsetsState insetsState);
@UnsupportedAppUsage
@@ -68,7 +68,6 @@ interface IWindowSession {
* to draw the window's contents.
*
* @param window The window being modified.
- * @param seq Ordering sequence number.
* @param attrs If non-null, new attributes to apply to the window.
* @param requestedWidth The width the window wants to be.
* @param requestedHeight The height the window wants to be.
@@ -106,7 +105,7 @@ interface IWindowSession {
* @return int Result flags: {@link WindowManagerGlobal#RELAYOUT_SHOW_FOCUS},
* {@link WindowManagerGlobal#RELAYOUT_FIRST_TIME}.
*/
- int relayout(IWindow window, int seq, in WindowManager.LayoutParams attrs,
+ int relayout(IWindow window, in WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewVisibility,
int flags, long frameNumber, out ClientWindowFrames outFrames,
out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl,
diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index 92772c1d7a44..efc0bd2785f4 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -16,16 +16,23 @@
package android.view;
+import static android.view.ImeFocusControllerProto.HAS_IME_FOCUS;
+import static android.view.ImeFocusControllerProto.NEXT_SERVED_VIEW;
+import static android.view.ImeFocusControllerProto.SERVED_VIEW;
+
import android.annotation.AnyThread;
import android.annotation.NonNull;
import android.annotation.UiThread;
import android.util.Log;
+import android.util.proto.ProtoOutputStream;
import android.view.inputmethod.InputMethodManager;
import com.android.internal.inputmethod.InputMethodDebug;
import com.android.internal.inputmethod.StartInputFlags;
import com.android.internal.inputmethod.StartInputReason;
+import java.util.Objects;
+
/**
* Responsible for IME focus handling inside {@link ViewRootImpl}.
* @hide
@@ -280,4 +287,12 @@ public final class ImeFocusController {
boolean hasImeFocus() {
return mHasImeFocus;
}
+
+ void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ proto.write(HAS_IME_FOCUS, mHasImeFocus);
+ proto.write(SERVED_VIEW, Objects.toString(mServedView));
+ proto.write(NEXT_SERVED_VIEW, Objects.toString(mNextServedView));
+ proto.end(token);
+ }
}
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index 82f60366a814..dd1a19458e1d 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -16,6 +16,9 @@
package android.view;
+import static android.view.ImeInsetsSourceConsumerProto.FOCUSED_EDITOR;
+import static android.view.ImeInsetsSourceConsumerProto.INSETS_SOURCE_CONSUMER;
+import static android.view.ImeInsetsSourceConsumerProto.IS_REQUESTED_VISIBLE_AWAITING_CONTROL;
import static android.view.InsetsController.AnimationType;
import static android.view.InsetsState.ITYPE_IME;
@@ -24,6 +27,7 @@ import android.inputmethodservice.InputMethodService;
import android.os.IBinder;
import android.os.Parcel;
import android.text.TextUtils;
+import android.util.proto.ProtoOutputStream;
import android.view.SurfaceControl.Transaction;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
@@ -111,7 +115,6 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
public @ShowResult int requestShow(boolean fromIme) {
// TODO: ResultReceiver for IME.
// TODO: Set mShowOnNextImeRender to automatically show IME and guard it with a flag.
-
if (getControl() == null) {
// If control is null, schedule to show IME when control is available.
mIsRequestedVisibleAwaitingControl = true;
@@ -227,6 +230,17 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
return Arrays.equals(parcel1.createByteArray(), parcel2.createByteArray());
}
+ @Override
+ public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ super.dumpDebug(proto, INSETS_SOURCE_CONSUMER);
+ if (mFocusedEditor != null) {
+ mFocusedEditor.dumpDebug(proto, FOCUSED_EDITOR);
+ }
+ proto.write(IS_REQUESTED_VISIBLE_AWAITING_CONTROL, mIsRequestedVisibleAwaitingControl);
+ proto.end(token);
+ }
+
private InputMethodManager getImm() {
return mController.getHost().getInputMethodManager();
}
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 6ffd892e4351..71899fab554c 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -17,6 +17,14 @@
package android.view;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.view.InsetsAnimationControlImplProto.CURRENT_ALPHA;
+import static android.view.InsetsAnimationControlImplProto.IS_CANCELLED;
+import static android.view.InsetsAnimationControlImplProto.IS_FINISHED;
+import static android.view.InsetsAnimationControlImplProto.PENDING_ALPHA;
+import static android.view.InsetsAnimationControlImplProto.PENDING_FRACTION;
+import static android.view.InsetsAnimationControlImplProto.PENDING_INSETS;
+import static android.view.InsetsAnimationControlImplProto.SHOWN_ON_FINISH;
+import static android.view.InsetsAnimationControlImplProto.TMP_MATRIX;
import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
import static android.view.InsetsController.AnimationType;
import static android.view.InsetsController.DEBUG;
@@ -38,6 +46,8 @@ import android.util.Log;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.SparseSetArray;
+import android.util.imetracing.ImeTracing;
+import android.util.proto.ProtoOutputStream;
import android.view.InsetsState.InternalInsetsSide;
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
import android.view.WindowInsets.Type.InsetsType;
@@ -48,6 +58,7 @@ import android.view.animation.Interpolator;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
+import java.util.Objects;
/**
* Implements {@link WindowInsetsAnimationController}
@@ -122,6 +133,10 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
mAnimationType = animationType;
mController.startAnimation(this, listener, types, mAnimation,
new Bounds(mHiddenInsets, mShownInsets));
+
+ if ((mTypes & WindowInsets.Type.ime()) != 0) {
+ ImeTracing.getInstance().triggerDump();
+ }
}
private boolean calculatePerceptible(Insets currentInsets, float currentAlpha) {
@@ -285,6 +300,20 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
return mAnimation;
}
+ @Override
+ public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ proto.write(IS_CANCELLED, mCancelled);
+ proto.write(IS_FINISHED, mFinished);
+ proto.write(TMP_MATRIX, Objects.toString(mTmpMatrix));
+ proto.write(PENDING_INSETS, Objects.toString(mPendingInsets));
+ proto.write(PENDING_FRACTION, mPendingFraction);
+ proto.write(SHOWN_ON_FINISH, mShownOnFinish);
+ proto.write(CURRENT_ALPHA, mCurrentAlpha);
+ proto.write(PENDING_ALPHA, mPendingAlpha);
+ proto.end(token);
+ }
+
WindowInsetsAnimationControlListener getListener() {
return mListener;
}
diff --git a/core/java/android/view/InsetsAnimationControlRunner.java b/core/java/android/view/InsetsAnimationControlRunner.java
index 0711c3e166d8..0275b521a2a2 100644
--- a/core/java/android/view/InsetsAnimationControlRunner.java
+++ b/core/java/android/view/InsetsAnimationControlRunner.java
@@ -16,6 +16,7 @@
package android.view;
+import android.util.proto.ProtoOutputStream;
import android.view.InsetsController.AnimationType;
import android.view.InsetsState.InternalInsetsType;
import android.view.WindowInsets.Type.InsetsType;
@@ -53,4 +54,14 @@ public interface InsetsAnimationControlRunner {
* @return The animation type this runner is running.
*/
@AnimationType int getAnimationType();
+
+ /**
+ *
+ * Export the state of classes that implement this interface into a protocol buffer
+ * output stream.
+ *
+ * @param proto Stream to write the state to
+ * @param fieldId FieldId of the implementation class
+ */
+ void dumpDebug(ProtoOutputStream proto, long fieldId);
}
diff --git a/core/java/android/view/InsetsAnimationThreadControlRunner.java b/core/java/android/view/InsetsAnimationThreadControlRunner.java
index 123604489da4..cc3cd278b267 100644
--- a/core/java/android/view/InsetsAnimationThreadControlRunner.java
+++ b/core/java/android/view/InsetsAnimationThreadControlRunner.java
@@ -25,6 +25,7 @@ import android.os.Handler;
import android.os.Trace;
import android.util.Log;
import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
import android.view.InsetsController.AnimationType;
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
import android.view.WindowInsets.Type.InsetsType;
@@ -122,6 +123,12 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro
@Override
@UiThread
+ public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ mControl.dumpDebug(proto, fieldId);
+ }
+
+ @Override
+ @UiThread
public int getTypes() {
return mControl.getTypes();
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 92eade3affaa..652781a310b9 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -16,6 +16,8 @@
package android.view;
+import static android.view.InsetsControllerProto.CONTROL;
+import static android.view.InsetsControllerProto.STATE;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.toInternalType;
@@ -41,6 +43,8 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
+import android.util.imetracing.ImeTracing;
+import android.util.proto.ProtoOutputStream;
import android.view.InsetsSourceConsumer.ShowResult;
import android.view.InsetsState.InternalInsetsType;
import android.view.SurfaceControl.Transaction;
@@ -298,6 +302,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@Override
public void onReady(WindowInsetsAnimationController controller, int types) {
+ if ((types & ime()) != 0) {
+ ImeTracing.getInstance().triggerDump();
+ }
+
mController = controller;
if (DEBUG) Log.d(TAG, "default animation onReady types: " + types);
@@ -812,6 +820,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@VisibleForTesting
public void show(@InsetsType int types, boolean fromIme) {
+ if (fromIme) {
+ ImeTracing.getInstance().triggerDump();
+ }
// Handle pending request ready in case there was one set.
if (fromIme && mPendingImeControlRequest != null) {
PendingControlRequest pendingRequest = mPendingImeControlRequest;
@@ -860,6 +871,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
void hide(@InsetsType int types, boolean fromIme) {
+ if (fromIme) {
+ ImeTracing.getInstance().triggerDump();
+ }
int typesReady = 0;
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
for (int i = internalTypes.size() - 1; i >= 0; i--) {
@@ -894,6 +908,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
listener.onCancelled(null);
return;
}
+ if (fromIme) {
+ ImeTracing.getInstance().triggerDump();
+ }
controlAnimationUnchecked(types, cancellationSignal, listener, mFrame, fromIme, durationMs,
interpolator, animationType, getLayoutInsetsDuringAnimationMode(types),
@@ -1292,6 +1309,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private void hideDirectly(
@InsetsType int types, boolean animationFinished, @AnimationType int animationType) {
+ if ((types & ime()) != 0) {
+ ImeTracing.getInstance().triggerDump();
+ }
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
for (int i = internalTypes.size() - 1; i >= 0; i--) {
getSourceConsumer(internalTypes.valueAt(i)).hide(animationFinished, animationType);
@@ -1299,6 +1319,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
private void showDirectly(@InsetsType int types) {
+ if ((types & ime()) != 0) {
+ ImeTracing.getInstance().triggerDump();
+ }
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
for (int i = internalTypes.size() - 1; i >= 0; i--) {
getSourceConsumer(internalTypes.valueAt(i)).show(false /* fromIme */);
@@ -1318,6 +1341,16 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
mState.dump(prefix + " ", pw);
}
+ void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ mState.dumpDebug(proto, STATE);
+ for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
+ InsetsAnimationControlRunner runner = mRunningAnimations.get(i).runner;
+ runner.dumpDebug(proto, CONTROL);
+ }
+ proto.end(token);
+ }
+
@VisibleForTesting
@Override
public void startAnimation(InsetsAnimationControlImpl controller,
@@ -1388,7 +1421,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
@Override
- public @Appearance int getSystemBarsBehavior() {
+ public @Behavior int getSystemBarsBehavior() {
return mHost.getSystemBarsBehavior();
}
diff --git a/core/java/android/view/InsetsFlags.java b/core/java/android/view/InsetsFlags.java
index 385b0bf960ef..5a64a5d5b3a6 100644
--- a/core/java/android/view/InsetsFlags.java
+++ b/core/java/android/view/InsetsFlags.java
@@ -16,13 +16,6 @@
package android.view;
-import static android.view.View.NAVIGATION_BAR_TRANSLUCENT;
-import static android.view.View.NAVIGATION_BAR_TRANSPARENT;
-import static android.view.View.STATUS_BAR_TRANSLUCENT;
-import static android.view.View.STATUS_BAR_TRANSPARENT;
-import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
-import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
-import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
@@ -76,44 +69,4 @@ public class InsetsFlags {
name = "SHOW_TRANSIENT_BARS_BY_SWIPE")
})
public @Behavior int behavior;
-
- /**
- * Converts system UI visibility to appearance.
- *
- * @param systemUiVisibility the system UI visibility to be converted.
- * @return the outcome {@link Appearance}
- */
- public static @Appearance int getAppearance(int systemUiVisibility) {
- int appearance = 0;
- appearance |= convertFlag(systemUiVisibility, SYSTEM_UI_FLAG_LOW_PROFILE,
- APPEARANCE_LOW_PROFILE_BARS);
- appearance |= convertFlag(systemUiVisibility, SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,
- APPEARANCE_LIGHT_STATUS_BARS);
- appearance |= convertFlag(systemUiVisibility, SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
- APPEARANCE_LIGHT_NAVIGATION_BARS);
- appearance |= convertNoFlag(systemUiVisibility,
- STATUS_BAR_TRANSLUCENT | STATUS_BAR_TRANSPARENT, APPEARANCE_OPAQUE_STATUS_BARS);
- appearance |= convertNoFlag(systemUiVisibility,
- NAVIGATION_BAR_TRANSLUCENT | NAVIGATION_BAR_TRANSPARENT,
- APPEARANCE_OPAQUE_NAVIGATION_BARS);
- return appearance;
- }
-
- /**
- * Converts the system UI visibility into an appearance flag if the given visibility contains
- * the given system UI flag.
- */
- private static @Appearance int convertFlag(int systemUiVisibility, int systemUiFlag,
- @Appearance int appearance) {
- return (systemUiVisibility & systemUiFlag) != 0 ? appearance : 0;
- }
-
- /**
- * Converts the system UI visibility into an appearance flag if the given visibility doesn't
- * contains the given system UI flag.
- */
- private static @Appearance int convertNoFlag(int systemUiVisibility, int systemUiFlag,
- @Appearance int appearance) {
- return (systemUiVisibility & systemUiFlag) == 0 ? appearance : 0;
- }
}
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index dbf75705c073..41cc8459a266 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -16,6 +16,10 @@
package android.view;
+import static android.view.InsetsSourceProto.FRAME;
+import static android.view.InsetsSourceProto.TYPE;
+import static android.view.InsetsSourceProto.VISIBLE;
+import static android.view.InsetsSourceProto.VISIBLE_FRAME;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
import static android.view.InsetsState.ITYPE_IME;
@@ -25,6 +29,7 @@ import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.proto.ProtoOutputStream;
import android.view.InsetsState.InternalInsetsType;
import java.io.PrintWriter;
@@ -183,6 +188,17 @@ public class InsetsSource implements Parcelable {
return false;
}
+ void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ proto.write(TYPE, InsetsState.typeToString(mType));
+ mFrame.dumpDebug(proto, FRAME);
+ if (mVisibleFrame != null) {
+ mVisibleFrame.dumpDebug(proto, VISIBLE_FRAME);
+ }
+ proto.write(VISIBLE, mVisible);
+ proto.end(token);
+ }
+
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix);
pw.print("InsetsSource type="); pw.print(InsetsState.typeToString(mType));
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index ba40459692f7..d7ceaf792198 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -19,6 +19,13 @@ package android.view;
import static android.view.InsetsController.ANIMATION_TYPE_NONE;
import static android.view.InsetsController.AnimationType;
import static android.view.InsetsController.DEBUG;
+import static android.view.InsetsSourceConsumerProto.HAS_WINDOW_FOCUS;
+import static android.view.InsetsSourceConsumerProto.INTERNAL_INSETS_TYPE;
+import static android.view.InsetsSourceConsumerProto.IS_REQUESTED_VISIBLE;
+import static android.view.InsetsSourceConsumerProto.PENDING_FRAME;
+import static android.view.InsetsSourceConsumerProto.PENDING_VISIBLE_FRAME;
+import static android.view.InsetsSourceConsumerProto.SOURCE_CONTROL;
+import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.getDefaultVisibility;
import static android.view.InsetsState.toPublicType;
@@ -28,6 +35,8 @@ import android.annotation.IntDef;
import android.annotation.Nullable;
import android.graphics.Rect;
import android.util.Log;
+import android.util.imetracing.ImeTracing;
+import android.util.proto.ProtoOutputStream;
import android.view.InsetsState.InternalInsetsType;
import android.view.SurfaceControl.Transaction;
import android.view.WindowInsets.Type.InsetsType;
@@ -319,6 +328,9 @@ public class InsetsSourceConsumer {
@VisibleForTesting(visibility = PACKAGE)
public boolean notifyAnimationFinished() {
+ if (mType == ITYPE_IME) {
+ ImeTracing.getInstance().triggerDump();
+ }
if (mPendingFrame != null) {
InsetsSource source = mState.getSource(mType);
source.setFrame(mPendingFrame);
@@ -360,4 +372,21 @@ public class InsetsSourceConsumer {
t.apply();
onPerceptible(mRequestedVisible);
}
+
+ void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ proto.write(INTERNAL_INSETS_TYPE, InsetsState.typeToString(mType));
+ proto.write(HAS_WINDOW_FOCUS, mHasWindowFocus);
+ proto.write(IS_REQUESTED_VISIBLE, mRequestedVisible);
+ if (mSourceControl != null) {
+ mSourceControl.dumpDebug(proto, SOURCE_CONTROL);
+ }
+ if (mPendingFrame != null) {
+ mPendingFrame.dumpDebug(proto, PENDING_FRAME);
+ }
+ if (mPendingVisibleFrame != null) {
+ mPendingVisibleFrame.dumpDebug(proto, PENDING_VISIBLE_FRAME);
+ }
+ proto.end(token);
+ }
}
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index 51b49214387a..b45bd3869f64 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -16,10 +16,17 @@
package android.view;
+import static android.graphics.PointProto.X;
+import static android.graphics.PointProto.Y;
+import static android.view.InsetsSourceControlProto.LEASH;
+import static android.view.InsetsSourceControlProto.POSITION;
+import static android.view.InsetsSourceControlProto.TYPE;
+
import android.annotation.Nullable;
import android.graphics.Point;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.proto.ProtoOutputStream;
import android.view.InsetsState.InternalInsetsType;
import java.io.PrintWriter;
@@ -120,4 +127,19 @@ public class InsetsSourceControl implements Parcelable {
return new InsetsSourceControl[size];
}
};
+
+ void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ proto.write(TYPE, InsetsState.typeToString(mType));
+
+ final long surfaceToken = proto.start(POSITION);
+ proto.write(X, mSurfacePosition.x);
+ proto.write(Y, mSurfacePosition.y);
+ proto.end(surfaceToken);
+
+ if (mLeash != null) {
+ mLeash.dumpDebug(proto, LEASH);
+ }
+ proto.end(token);
+ }
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index c5d0a10bb108..eabb71851303 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -16,6 +16,8 @@
package android.view;
+import static android.view.InsetsStateProto.DISPLAY_FRAME;
+import static android.view.InsetsStateProto.SOURCES;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
@@ -41,6 +43,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArraySet;
import android.util.SparseIntArray;
+import android.util.proto.ProtoOutputStream;
import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
@@ -545,6 +548,16 @@ public class InsetsState implements Parcelable {
}
}
+ void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ InsetsSource source = mSources[ITYPE_IME];
+ if (source != null) {
+ source.dumpDebug(proto, SOURCES);
+ }
+ mDisplayFrame.dumpDebug(proto, DISPLAY_FRAME);
+ proto.end(token);
+ }
+
public static String typeToString(@InternalInsetsType int type) {
switch (type) {
case ITYPE_STATUS_BAR:
diff --git a/core/java/android/view/OnReceiveContentCallback.java b/core/java/android/view/OnReceiveContentCallback.java
new file mode 100644
index 000000000000..73bcb93d39d0
--- /dev/null
+++ b/core/java/android/view/OnReceiveContentCallback.java
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.net.Uri;
+import android.os.Bundle;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Callback for apps to implement handling for insertion of content. "Content" here refers to both
+ * text and non-text (plain/styled text, HTML, images, videos, audio files, etc).
+ *
+ * <p>This callback can be attached to different types of UI components using
+ * {@link View#setOnReceiveContentCallback}.
+ *
+ * <p>For editable {@link android.widget.TextView} components, implementations can extend from
+ * {@link android.widget.TextViewOnReceiveContentCallback} to reuse default platform behavior for
+ * handling text.
+ *
+ * <p>Example implementation:<br>
+ * <pre class="prettyprint">
+ * public class MyOnReceiveContentCallback implements OnReceiveContentCallback&lt;TextView&gt; {
+ *
+ * private static final Set&lt;String&gt; SUPPORTED_MIME_TYPES = Collections.unmodifiableSet(
+ * Set.of("image/*", "video/*"));
+ *
+ * &#64;NonNull
+ * &#64;Override
+ * public Set&lt;String&gt; getSupportedMimeTypes() {
+ * return SUPPORTED_MIME_TYPES;
+ * }
+ *
+ * &#64;Override
+ * public boolean onReceiveContent(@NonNull TextView view, @NonNull Payload payload) {
+ * // ... app-specific logic to handle the content in the payload ...
+ * }
+ * }
+ * </pre>
+ *
+ * @param <T> The type of {@link View} with which this receiver can be associated.
+ */
+public interface OnReceiveContentCallback<T extends View> {
+ /**
+ * Receive the given content.
+ *
+ * <p>This function will only be invoked if the MIME type of the content is in the set of
+ * types returned by {@link #getSupportedMimeTypes}.
+ *
+ * <p>For text, if the view has a selection, the selection should be overwritten by the clip; if
+ * there's no selection, this method should insert the content at the current cursor position.
+ *
+ * <p>For non-text content (e.g. an image), the content may be inserted inline, or it may be
+ * added as an attachment (could potentially be shown in a completely separate view).
+ *
+ * @param view The view where the content insertion was requested.
+ * @param payload The content to insert and related metadata.
+ *
+ * @return Returns true if some or all of the content is accepted for insertion. If accepted,
+ * actual insertion may be handled asynchronously in the background and may or may not result in
+ * successful insertion. For example, the app may not end up inserting an accepted item if it
+ * exceeds the app's size limit for that type of content.
+ */
+ boolean onReceiveContent(@NonNull T view, @NonNull Payload payload);
+
+ /**
+ * Returns the MIME types that can be handled by this callback.
+ *
+ * <p>The {@link #onReceiveContent} callback method will only be invoked if the MIME type of the
+ * content is in the set of supported types returned here.
+ *
+ * <p>Different platform features (e.g. pasting from the clipboard, inserting stickers from the
+ * keyboard, etc) may use this function to conditionally alter their behavior. For example, the
+ * keyboard may choose to hide its UI for inserting GIFs if the input field that has focus has
+ * a {@link OnReceiveContentCallback} set and the MIME types returned from this function don't
+ * include "image/gif".
+ *
+ * <p><em>Note: MIME type matching in the Android framework is case-sensitive, unlike formal RFC
+ * MIME types. As a result, you should always write your MIME types with lower case letters, or
+ * use {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to lower
+ * case.</em>
+ *
+ * @param view The target view.
+ * @return An immutable set with the MIME types supported by this callback. The returned MIME
+ * types may contain wildcards such as "text/*", "image/*", etc.
+ */
+ @SuppressLint("CallbackMethodName")
+ @NonNull
+ Set<String> getSupportedMimeTypes(@NonNull T view);
+
+ /**
+ * Returns true if at least one of the MIME types of the given clip is
+ * {@link #getSupportedMimeTypes supported} by this receiver.
+ *
+ * @hide
+ */
+ default boolean supports(@NonNull T view, @NonNull ClipDescription description) {
+ for (String supportedMimeType : getSupportedMimeTypes(view)) {
+ if (description.hasMimeType(supportedMimeType)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Holds all the relevant data for a request to {@link OnReceiveContentCallback}.
+ */
+ final class Payload {
+
+ /**
+ * Specifies the UI through which content is being inserted.
+ *
+ * @hide
+ */
+ @IntDef(prefix = {"SOURCE_"}, value = {SOURCE_CLIPBOARD, SOURCE_INPUT_METHOD,
+ SOURCE_DRAG_AND_DROP, SOURCE_AUTOFILL, SOURCE_PROCESS_TEXT})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Source {}
+
+ /**
+ * Specifies that the operation was triggered by a paste from the clipboard (e.g. "Paste" or
+ * "Paste as plain text" action in the insertion/selection menu).
+ */
+ public static final int SOURCE_CLIPBOARD = 0;
+
+ /**
+ * Specifies that the operation was triggered from the soft keyboard (also known as input
+ * method editor or IME). See https://developer.android.com/guide/topics/text/image-keyboard
+ * for more info.
+ */
+ public static final int SOURCE_INPUT_METHOD = 1;
+
+ /**
+ * Specifies that the operation was triggered by the drag/drop framework. See
+ * https://developer.android.com/guide/topics/ui/drag-drop for more info.
+ */
+ public static final int SOURCE_DRAG_AND_DROP = 2;
+
+ /**
+ * Specifies that the operation was triggered by the autofill framework. See
+ * https://developer.android.com/guide/topics/text/autofill for more info.
+ */
+ public static final int SOURCE_AUTOFILL = 3;
+
+ /**
+ * Specifies that the operation was triggered by a result from a
+ * {@link android.content.Intent#ACTION_PROCESS_TEXT PROCESS_TEXT} action in the selection
+ * menu.
+ */
+ public static final int SOURCE_PROCESS_TEXT = 4;
+
+ /**
+ * Returns the symbolic name of the given source.
+ *
+ * @hide
+ */
+ static String sourceToString(@Source int source) {
+ switch (source) {
+ case SOURCE_CLIPBOARD: return "SOURCE_CLIPBOARD";
+ case SOURCE_INPUT_METHOD: return "SOURCE_INPUT_METHOD";
+ case SOURCE_DRAG_AND_DROP: return "SOURCE_DRAG_AND_DROP";
+ case SOURCE_AUTOFILL: return "SOURCE_AUTOFILL";
+ case SOURCE_PROCESS_TEXT: return "SOURCE_PROCESS_TEXT";
+ }
+ return String.valueOf(source);
+ }
+
+ /**
+ * Flags to configure the insertion behavior.
+ *
+ * @hide
+ */
+ @IntDef(flag = true, prefix = {"FLAG_"}, value = {FLAG_CONVERT_TO_PLAIN_TEXT})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Flags {}
+
+ /**
+ * Flag requesting that the content should be converted to plain text prior to inserting.
+ */
+ public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1 << 0;
+
+ /**
+ * Returns the symbolic names of the set flags or {@code "0"} if no flags are set.
+ *
+ * @hide
+ */
+ static String flagsToString(@Flags int flags) {
+ if ((flags & FLAG_CONVERT_TO_PLAIN_TEXT) != 0) {
+ return "FLAG_CONVERT_TO_PLAIN_TEXT";
+ }
+ return String.valueOf(flags);
+ }
+
+ /**
+ * The data to be inserted.
+ */
+ @NonNull private final ClipData mClip;
+
+ /**
+ * The source of the operation. See {@code SOURCE_} constants.
+ */
+ private final @Source int mSource;
+
+ /**
+ * Optional flags that control the insertion behavior. See {@code FLAG_} constants.
+ */
+ private final @Flags int mFlags;
+
+ /**
+ * Optional http/https URI for the content that may be provided by the IME. This is only
+ * populated if the source is {@link #SOURCE_INPUT_METHOD} and if a non-empty
+ * {@link android.view.inputmethod.InputContentInfo#getLinkUri linkUri} was passed by the
+ * IME.
+ */
+ @Nullable
+ private final Uri mLinkUri;
+
+ /**
+ * Optional additional metadata. If the source is {@link #SOURCE_INPUT_METHOD}, this will
+ * include the {@link android.view.inputmethod.InputConnection#commitContent opts} passed by
+ * the IME.
+ */
+ @Nullable
+ private final Bundle mExtras;
+
+ private Payload(Builder b) {
+ this.mClip = Objects.requireNonNull(b.mClip);
+ this.mSource = Preconditions.checkArgumentInRange(b.mSource, 0, SOURCE_PROCESS_TEXT,
+ "source");
+ this.mFlags = Preconditions.checkFlagsArgument(b.mFlags, FLAG_CONVERT_TO_PLAIN_TEXT);
+ this.mLinkUri = b.mLinkUri;
+ this.mExtras = b.mExtras;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "Payload{"
+ + "clip=" + mClip.getDescription()
+ + ", source=" + sourceToString(mSource)
+ + ", flags=" + flagsToString(mFlags)
+ + ", linkUri=" + mLinkUri
+ + ", extras=" + mExtras
+ + "}";
+ }
+
+ /**
+ * The data to be inserted.
+ */
+ public @NonNull ClipData getClip() {
+ return mClip;
+ }
+
+ /**
+ * The source of the operation. See {@code SOURCE_} constants.
+ */
+ public @Source int getSource() {
+ return mSource;
+ }
+
+ /**
+ * Optional flags that control the insertion behavior. See {@code FLAG_} constants.
+ */
+ public @Flags int getFlags() {
+ return mFlags;
+ }
+
+ /**
+ * Optional http/https URI for the content that may be provided by the IME. This is only
+ * populated if the source is {@link #SOURCE_INPUT_METHOD} and if a non-empty
+ * {@link android.view.inputmethod.InputContentInfo#getLinkUri linkUri} was passed by the
+ * IME.
+ */
+ public @Nullable Uri getLinkUri() {
+ return mLinkUri;
+ }
+
+ /**
+ * Optional additional metadata. If the source is {@link #SOURCE_INPUT_METHOD}, this will
+ * include the {@link android.view.inputmethod.InputConnection#commitContent opts} passed by
+ * the IME.
+ */
+ public @Nullable Bundle getExtras() {
+ return mExtras;
+ }
+
+ /**
+ * Builder for {@link Payload}.
+ */
+ public static final class Builder {
+ @NonNull private final ClipData mClip;
+ private final @Source int mSource;
+ private @Flags int mFlags;
+ @Nullable private Uri mLinkUri;
+ @Nullable private Bundle mExtras;
+
+ /**
+ * Creates a new builder.
+ * @param clip The data to insert.
+ * @param source The source of the operation. See {@code SOURCE_} constants.
+ */
+ public Builder(@NonNull ClipData clip, @Source int source) {
+ mClip = clip;
+ mSource = source;
+ }
+
+ /**
+ * Sets flags that control content insertion behavior.
+ * @param flags Optional flags to configure the insertion behavior. Use 0 for default
+ * behavior. See {@code FLAG_} constants.
+ * @return this builder
+ */
+ @NonNull
+ public Builder setFlags(@Flags int flags) {
+ mFlags = flags;
+ return this;
+ }
+
+ /**
+ * Sets the http/https URI for the content. See
+ * {@link android.view.inputmethod.InputContentInfo#getLinkUri} for more info.
+ * @param linkUri Optional http/https URI for the content.
+ * @return this builder
+ */
+ @NonNull
+ public Builder setLinkUri(@Nullable Uri linkUri) {
+ mLinkUri = linkUri;
+ return this;
+ }
+
+ /**
+ * Sets additional metadata.
+ * @param extras Optional bundle with additional metadata.
+ * @return this builder
+ */
+ @NonNull
+ public Builder setExtras(@Nullable Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
+ /**
+ * @return A new {@link Payload} instance with the data from this builder.
+ */
+ @NonNull
+ public Payload build() {
+ return new Payload(this);
+ }
+ }
+ }
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e7e28ac98234..c430a4d57338 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3995,89 +3995,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* @hide
- *
- * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
- * out of the public fields to keep the undefined bits out of the developer's way.
- *
- * Flag to specify that the status bar is displayed in transient mode.
- */
- public static final int STATUS_BAR_TRANSIENT = 0x04000000;
-
- /**
- * @hide
- *
- * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
- * out of the public fields to keep the undefined bits out of the developer's way.
- *
- * Flag to specify that the navigation bar is displayed in transient mode.
- */
- @UnsupportedAppUsage
- public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000;
-
- /**
- * @hide
- *
- * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
- * out of the public fields to keep the undefined bits out of the developer's way.
- *
- * Flag to specify that the hidden status bar would like to be shown.
- */
- public static final int STATUS_BAR_UNHIDE = 0x10000000;
-
- /**
- * @hide
- *
- * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
- * out of the public fields to keep the undefined bits out of the developer's way.
- *
- * Flag to specify that the hidden navigation bar would like to be shown.
- */
- public static final int NAVIGATION_BAR_UNHIDE = 0x20000000;
-
- /**
- * @hide
- *
- * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
- * out of the public fields to keep the undefined bits out of the developer's way.
- *
- * Flag to specify that the status bar is displayed in translucent mode.
- */
- public static final int STATUS_BAR_TRANSLUCENT = 0x40000000;
-
- /**
- * @hide
- *
- * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
- * out of the public fields to keep the undefined bits out of the developer's way.
- *
- * Flag to specify that the navigation bar is displayed in translucent mode.
- */
- public static final int NAVIGATION_BAR_TRANSLUCENT = 0x80000000;
-
- /**
- * @hide
- *
- * Makes navigation bar transparent (but not the status bar).
- */
- public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000;
-
- /**
- * @hide
- *
- * Makes status bar transparent (but not the navigation bar).
- */
- public static final int STATUS_BAR_TRANSPARENT = 0x00000008;
-
- /**
- * @hide
- *
- * Makes both status bar and navigation bar transparent.
- */
- public static final int SYSTEM_UI_TRANSPARENT = NAVIGATION_BAR_TRANSPARENT
- | STATUS_BAR_TRANSPARENT;
-
- /**
- * @hide
*/
public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7;
@@ -4302,31 +4219,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
name = "STATUS_BAR_DISABLE_RECENT"),
@ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SEARCH,
equals = STATUS_BAR_DISABLE_SEARCH,
- name = "STATUS_BAR_DISABLE_SEARCH"),
- @ViewDebug.FlagToString(mask = STATUS_BAR_TRANSIENT,
- equals = STATUS_BAR_TRANSIENT,
- name = "STATUS_BAR_TRANSIENT"),
- @ViewDebug.FlagToString(mask = NAVIGATION_BAR_TRANSIENT,
- equals = NAVIGATION_BAR_TRANSIENT,
- name = "NAVIGATION_BAR_TRANSIENT"),
- @ViewDebug.FlagToString(mask = STATUS_BAR_UNHIDE,
- equals = STATUS_BAR_UNHIDE,
- name = "STATUS_BAR_UNHIDE"),
- @ViewDebug.FlagToString(mask = NAVIGATION_BAR_UNHIDE,
- equals = NAVIGATION_BAR_UNHIDE,
- name = "NAVIGATION_BAR_UNHIDE"),
- @ViewDebug.FlagToString(mask = STATUS_BAR_TRANSLUCENT,
- equals = STATUS_BAR_TRANSLUCENT,
- name = "STATUS_BAR_TRANSLUCENT"),
- @ViewDebug.FlagToString(mask = NAVIGATION_BAR_TRANSLUCENT,
- equals = NAVIGATION_BAR_TRANSLUCENT,
- name = "NAVIGATION_BAR_TRANSLUCENT"),
- @ViewDebug.FlagToString(mask = NAVIGATION_BAR_TRANSPARENT,
- equals = NAVIGATION_BAR_TRANSPARENT,
- name = "NAVIGATION_BAR_TRANSPARENT"),
- @ViewDebug.FlagToString(mask = STATUS_BAR_TRANSPARENT,
- equals = STATUS_BAR_TRANSPARENT,
- name = "STATUS_BAR_TRANSPARENT")
+ name = "STATUS_BAR_DISABLE_SEARCH")
}, formatToHexString = true)
@SystemUiVisibility
int mSystemUiVisibility;
@@ -4355,14 +4248,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
STATUS_BAR_DISABLE_CLOCK,
STATUS_BAR_DISABLE_RECENT,
STATUS_BAR_DISABLE_SEARCH,
- STATUS_BAR_TRANSIENT,
- NAVIGATION_BAR_TRANSIENT,
- STATUS_BAR_UNHIDE,
- NAVIGATION_BAR_UNHIDE,
- STATUS_BAR_TRANSLUCENT,
- NAVIGATION_BAR_TRANSLUCENT,
- NAVIGATION_BAR_TRANSPARENT,
- STATUS_BAR_TRANSPARENT,
})
@Retention(RetentionPolicy.SOURCE)
public @interface SystemUiVisibility {}
@@ -5358,6 +5243,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@InputSourceClass
int mUnbufferedInputSource = InputDevice.SOURCE_CLASS_NONE;
+ @Nullable
+ private OnReceiveContentCallback<? extends View> mOnReceiveContentCallback;
+
/**
* Simple constructor to use when creating a view from code.
*
@@ -9113,6 +9001,36 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Returns the callback used for handling insertion of content into this view. See
+ * {@link #setOnReceiveContentCallback} for more info.
+ *
+ * @return The callback for handling insertion of content. Returns null if no callback has been
+ * {@link #setOnReceiveContentCallback set}.
+ */
+ @Nullable
+ public OnReceiveContentCallback<? extends View> getOnReceiveContentCallback() {
+ return mOnReceiveContentCallback;
+ }
+
+ /**
+ * Sets the callback to handle insertion of content into this view.
+ *
+ * <p>Depending on the view, this callback may be invoked for scenarios such as content
+ * insertion from the IME, Autofill, etc.
+ *
+ * <p>The callback will only be invoked if the MIME type of the content is
+ * {@link OnReceiveContentCallback#getSupportedMimeTypes declared as supported} by the callback.
+ * If the content type is not supported by the callback, the default platform handling will be
+ * executed instead.
+ *
+ * @param callback The callback to use. This can be null to reset to the default behavior.
+ */
+ public void setOnReceiveContentCallback(
+ @Nullable OnReceiveContentCallback<? extends View> callback) {
+ mOnReceiveContentCallback = callback;
+ }
+
+ /**
* Automatically fills the content of this view with the {@code value}.
*
* <p>Views support the Autofill Framework mainly by:
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4176e887c0e7..88bd1c113704 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -33,6 +33,23 @@ import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewRootImplProto.ADDED;
+import static android.view.ViewRootImplProto.APP_VISIBLE;
+import static android.view.ViewRootImplProto.CUR_SCROLL_Y;
+import static android.view.ViewRootImplProto.DISPLAY_ID;
+import static android.view.ViewRootImplProto.HEIGHT;
+import static android.view.ViewRootImplProto.IS_ANIMATING;
+import static android.view.ViewRootImplProto.IS_DRAWING;
+import static android.view.ViewRootImplProto.LAST_WINDOW_INSETS;
+import static android.view.ViewRootImplProto.PENDING_DISPLAY_CUTOUT;
+import static android.view.ViewRootImplProto.REMOVED;
+import static android.view.ViewRootImplProto.SCROLL_Y;
+import static android.view.ViewRootImplProto.SOFT_INPUT_MODE;
+import static android.view.ViewRootImplProto.VIEW;
+import static android.view.ViewRootImplProto.VISIBLE_RECT;
+import static android.view.ViewRootImplProto.WIDTH;
+import static android.view.ViewRootImplProto.WINDOW_ATTRIBUTES;
+import static android.view.ViewRootImplProto.WIN_FRAME;
import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
@@ -61,6 +78,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ClientSideProto.IME_FOCUS_CONTROLLER;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ClientSideProto.INSETS_CONTROLLER;
import android.Manifest;
import android.animation.LayoutTransition;
@@ -127,6 +146,8 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.TypedValue;
+import android.util.imetracing.ImeTracing;
+import android.util.proto.ProtoOutputStream;
import android.view.InputDevice.InputSourceClass;
import android.view.InsetsState.InternalInsetsType;
import android.view.Surface.OutOfResourcesException;
@@ -164,6 +185,7 @@ import android.window.ClientWindowFrames;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.inputmethod.InputMethodDebug;
import com.android.internal.os.IResultReceiver;
import com.android.internal.os.SomeArgs;
import com.android.internal.policy.DecorView;
@@ -182,6 +204,7 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
+import java.util.Objects;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
@@ -339,8 +362,6 @@ public final class ViewRootImpl implements ViewParent,
final int mTargetSdkVersion;
- int mSeq;
-
@UnsupportedAppUsage
View mView;
@@ -648,7 +669,6 @@ public final class ViewRootImpl implements ViewParent,
private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
static final class SystemUiVisibilityInfo {
- int seq;
int globalVisibility;
int localValue;
int localChanges;
@@ -995,7 +1015,7 @@ public final class ViewRootImpl implements ViewParent,
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
adjustLayoutParamsForCompatibility(mWindowAttributes);
- res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
+ res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrames.frame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mDisplayCutout, inputChannel,
@@ -7390,7 +7410,7 @@ public final class ViewRootImpl implements ViewParent,
frameNumber = mSurface.getNextFrameNumber();
}
- int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,
+ int relayoutResult = mWindowSession.relayout(mWindow, params,
(int) (mView.getMeasuredWidth() * appScale + 0.5f),
(int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
@@ -7520,6 +7540,38 @@ public final class ViewRootImpl implements ViewParent,
mView.debug();
}
+ /**
+ * Export the state of {@link ViewRootImpl} and other relevant classes into a protocol buffer
+ * output stream.
+ *
+ * @param proto Stream to write the state to
+ * @param fieldId FieldId of ViewRootImpl as defined in the parent message
+ */
+ @GuardedBy("this")
+ public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ proto.write(VIEW, Objects.toString(mView));
+ proto.write(DISPLAY_ID, mDisplay.getDisplayId());
+ proto.write(APP_VISIBLE, mAppVisible);
+ proto.write(HEIGHT, mHeight);
+ proto.write(WIDTH, mWidth);
+ proto.write(IS_ANIMATING, mIsAnimating);
+ mVisRect.dumpDebug(proto, VISIBLE_RECT);
+ proto.write(IS_DRAWING, mIsDrawing);
+ proto.write(ADDED, mAdded);
+ mWinFrame.dumpDebug(proto, WIN_FRAME);
+ mPendingDisplayCutout.get().dumpDebug(proto, PENDING_DISPLAY_CUTOUT);
+ proto.write(LAST_WINDOW_INSETS, Objects.toString(mLastWindowInsets));
+ proto.write(SOFT_INPUT_MODE, InputMethodDebug.softInputModeToString(mSoftInputMode));
+ proto.write(SCROLL_Y, mScrollY);
+ proto.write(CUR_SCROLL_Y, mCurScrollY);
+ proto.write(REMOVED, mRemoved);
+ mWindowAttributes.dumpDebug(proto, WINDOW_ATTRIBUTES);
+ proto.end(token);
+ mInsetsController.dumpDebug(proto, INSETS_CONTROLLER);
+ mImeFocusController.dumpDebug(proto, IME_FOCUS_CONTROLLER);
+ }
+
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
String innerPrefix = prefix + " ";
writer.println(prefix + "ViewRoot:");
@@ -8460,17 +8512,6 @@ public final class ViewRootImpl implements ViewParent,
mHandler.sendMessage(msg);
}
- // TODO(118118435): Remove this after migration
- public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
- int localValue, int localChanges) {
- SystemUiVisibilityInfo args = new SystemUiVisibilityInfo();
- args.seq = seq;
- args.globalVisibility = globalVisibility;
- args.localValue = localValue;
- args.localChanges = localChanges;
- mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
- }
-
public void dispatchCheckFocus() {
if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
// This will result in a call to checkFocus() below.
@@ -9094,6 +9135,9 @@ public final class ViewRootImpl implements ViewParent,
@Override
public void showInsets(@InsetsType int types, boolean fromIme) {
+ if (fromIme) {
+ ImeTracing.getInstance().triggerDump();
+ }
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.showInsets(types, fromIme);
@@ -9102,6 +9146,9 @@ public final class ViewRootImpl implements ViewParent,
@Override
public void hideInsets(@InsetsType int types, boolean fromIme) {
+ if (fromIme) {
+ ImeTracing.getInstance().triggerDump();
+ }
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.hideInsets(types, fromIme);
@@ -9229,16 +9276,6 @@ public final class ViewRootImpl implements ViewParent,
}
@Override
- public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
- int localValue, int localChanges) {
- final ViewRootImpl viewAncestor = mViewAncestor.get();
- if (viewAncestor != null) {
- viewAncestor.dispatchSystemUiVisibilityChanged(seq, globalVisibility,
- localValue, localChanges);
- }
- }
-
- @Override
public void dispatchWindowShown() {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 0d62da6bc8e3..e96e98b437a1 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -3994,4 +3994,15 @@ public interface WindowManager extends ViewManager {
}
}
}
+
+ /**
+ * Holds the WM lock for the specified amount of milliseconds.
+ * Intended for use by the tests that need to imitate lock contention.
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.INJECT_EVENTS)
+ default void holdLock(int durationMs) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index f57ee65948c0..59e022645544 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -281,4 +281,13 @@ public final class WindowManagerImpl implements WindowManager {
throw e.rethrowFromSystemServer();
}
}
+
+ @Override
+ public void holdLock(int durationMs) {
+ try {
+ WindowManagerGlobal.getWindowManagerService().holdLock(durationMs);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index b70cb015a275..dbd8184e57bb 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -129,7 +129,7 @@ public class WindowlessWindowManager implements IWindowSession {
* IWindowSession implementation.
*/
@Override
- public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
+ public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
Rect outStableInsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
@@ -165,18 +165,18 @@ public class WindowlessWindowManager implements IWindowSession {
* IWindowSession implementation. Currently this class doesn't need to support for multi-user.
*/
@Override
- public int addToDisplayAsUser(IWindow window, int seq, WindowManager.LayoutParams attrs,
+ public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, int userId, Rect outFrame,
Rect outContentInsets, Rect outStableInsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
- return addToDisplay(window, seq, attrs, viewVisibility, displayId,
+ return addToDisplay(window, attrs, viewVisibility, displayId,
outFrame, outContentInsets, outStableInsets, outDisplayCutout, outInputChannel,
outInsetsState, outActiveControls);
}
@Override
- public int addToDisplayWithoutInputChannel(android.view.IWindow window, int seq,
+ public int addToDisplayWithoutInputChannel(android.view.IWindow window,
android.view.WindowManager.LayoutParams attrs, int viewVisibility, int layerStackId,
android.graphics.Rect outContentInsets, android.graphics.Rect outStableInsets,
android.view.InsetsState insetsState) {
@@ -223,7 +223,7 @@ public class WindowlessWindowManager implements IWindowSession {
}
@Override
- public int relayout(IWindow window, int seq, WindowManager.LayoutParams inAttrs,
+ public int relayout(IWindow window, WindowManager.LayoutParams inAttrs,
int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index eef27262c699..73636f81369f 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -16,7 +16,10 @@
package android.view.inputmethod;
+import static android.view.OnReceiveContentCallback.Payload.SOURCE_INPUT_METHOD;
+
import android.annotation.CallSuper;
+import android.content.ClipData;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
@@ -34,6 +37,7 @@ import android.util.Log;
import android.util.LogPrinter;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
+import android.view.OnReceiveContentCallback;
import android.view.View;
class ComposingText implements NoCopySpan {
@@ -870,9 +874,41 @@ public class BaseInputConnection implements InputConnection {
}
/**
- * The default implementation does nothing.
+ * Default implementation which invokes the target view's {@link OnReceiveContentCallback} if
+ * it is {@link View#setOnReceiveContentCallback set} and supports the MIME type of the given
+ * content; otherwise, simply returns false.
*/
public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
- return false;
+ @SuppressWarnings("unchecked") final OnReceiveContentCallback<View> receiver =
+ (OnReceiveContentCallback<View>) mTargetView.getOnReceiveContentCallback();
+ if (receiver == null) {
+ if (DEBUG) {
+ Log.d(TAG, "Can't insert content from IME; no callback");
+ }
+ return false;
+ }
+ if (!receiver.supports(mTargetView, inputContentInfo.getDescription())) {
+ if (DEBUG) {
+ Log.d(TAG, "Can't insert content from IME; callback doesn't support MIME type: "
+ + inputContentInfo.getDescription());
+ }
+ return false;
+ }
+ if ((flags & InputConnection.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
+ try {
+ inputContentInfo.requestPermission();
+ } catch (Exception e) {
+ Log.w(TAG, "Can't insert content from IME; requestPermission() failed", e);
+ return false;
+ }
+ }
+ final ClipData clip = new ClipData(inputContentInfo.getDescription(),
+ new ClipData.Item(inputContentInfo.getContentUri()));
+ final OnReceiveContentCallback.Payload payload =
+ new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_INPUT_METHOD)
+ .setLinkUri(inputContentInfo.getLinkUri())
+ .setExtras(opts)
+ .build();
+ return receiver.onReceiveContent(mTargetView, payload);
}
}
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 104bc4347c29..7dbf69369996 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -17,6 +17,12 @@
package android.view.inputmethod;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.view.inputmethod.EditorInfoProto.FIELD_ID;
+import static android.view.inputmethod.EditorInfoProto.IME_OPTIONS;
+import static android.view.inputmethod.EditorInfoProto.INPUT_TYPE;
+import static android.view.inputmethod.EditorInfoProto.PACKAGE_NAME;
+import static android.view.inputmethod.EditorInfoProto.PRIVATE_IME_OPTIONS;
+import static android.view.inputmethod.EditorInfoProto.TARGET_INPUT_METHOD_USER_ID;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -32,6 +38,7 @@ import android.text.InputType;
import android.text.ParcelableSpan;
import android.text.TextUtils;
import android.util.Printer;
+import android.util.proto.ProtoOutputStream;
import android.view.View;
import android.view.autofill.AutofillId;
@@ -795,6 +802,26 @@ public class EditorInfo implements InputType, Parcelable {
}
/**
+ * Export the state of {@link EditorInfo} into a protocol buffer output stream.
+ *
+ * @param proto Stream to write the state to
+ * @param fieldId FieldId of ViewRootImpl as defined in the parent message
+ * @hide
+ */
+ public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ proto.write(INPUT_TYPE, inputType);
+ proto.write(IME_OPTIONS, imeOptions);
+ proto.write(PRIVATE_IME_OPTIONS, privateImeOptions);
+ proto.write(PACKAGE_NAME, packageName);
+ proto.write(FIELD_ID, this.fieldId);
+ if (targetInputMethodUser != null) {
+ proto.write(TARGET_INPUT_METHOD_USER_ID, targetInputMethodUser.getIdentifier());
+ }
+ proto.end(token);
+ }
+
+ /**
* Write debug output of this object.
*/
public void dump(Printer pw, String prefix) {
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 8adb7e59b713..b8f04159faa9 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -18,6 +18,17 @@ package android.view.inputmethod;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
+import static android.util.imetracing.ImeTracing.PROTO_ARG;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ClientSideProto.DISPLAY_ID;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ClientSideProto.EDITOR_INFO;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ClientSideProto.IME_INSETS_SOURCE_CONSUMER;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ClientSideProto.INPUT_METHOD_MANAGER;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ClientSideProto.VIEW_ROOT_IMPL;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ClientsProto.CLIENT;
+import static android.view.inputmethod.InputMethodManagerProto.ACTIVE;
+import static android.view.inputmethod.InputMethodManagerProto.CUR_ID;
+import static android.view.inputmethod.InputMethodManagerProto.FULLSCREEN_MODE;
+import static android.view.inputmethod.InputMethodManagerProto.SERVED_CONNECTING;
import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITHOUT_CONNECTION;
import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_CONNECTION;
@@ -62,6 +73,8 @@ import android.util.Pools.SimplePool;
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.SparseArray;
+import android.util.imetracing.ImeTracing;
+import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.ImeFocusController;
import android.view.ImeInsetsSourceConsumer;
@@ -564,6 +577,7 @@ public final class InputMethodManager {
@StartInputFlags int startInputFlags, @SoftInputModeFlags int softInputMode,
int windowFlags) {
final View servedView;
+ ImeTracing.getInstance().triggerDump();
synchronized (mH) {
mCurrentTextBoxAttribute = null;
mCompletions = null;
@@ -1084,6 +1098,11 @@ public final class InputMethodManager {
mH.obtainMessage(MSG_UPDATE_ACTIVITY_VIEW_TO_SCREEN_MATRIX, bindSequence, 0,
matrixValues).sendToTarget();
}
+
+ @Override
+ public void setImeTraceEnabled(boolean enabled) {
+ ImeTracing.getInstance().setEnabled(enabled);
+ }
};
final InputConnection mDummyInputConnection = new BaseInputConnection(this, false);
@@ -1652,6 +1671,7 @@ public final class InputMethodManager {
* {@link #RESULT_HIDDEN}.
*/
public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
+ ImeTracing.getInstance().triggerDump();
// Re-dispatch if there is a context mismatch.
final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
if (fallbackImm != null) {
@@ -1757,6 +1777,7 @@ public final class InputMethodManager {
*/
public boolean hideSoftInputFromWindow(IBinder windowToken, int flags,
ResultReceiver resultReceiver) {
+ ImeTracing.getInstance().triggerDump();
checkFocus();
synchronized (mH) {
final View servedView = getServedViewLocked();
@@ -3108,6 +3129,10 @@ public final class InputMethodManager {
}
void doDump(FileDescriptor fd, PrintWriter fout, String[] args) {
+ if (processDump(fd, args)) {
+ return;
+ }
+
final Printer p = new PrintWriterPrinter(fout);
p.println("Input method client state for " + this + ":");
@@ -3202,4 +3227,74 @@ public final class InputMethodManager {
return sb.toString();
}
+
+ /**
+ * Checks the args to see if a proto-based ime dump was requested and writes the client side
+ * ime dump to the given {@link FileDescriptor}.
+ *
+ * @return {@code true} if a proto-based ime dump was requested.
+ */
+ private boolean processDump(final FileDescriptor fd, final String[] args) {
+ if (args == null) {
+ return false;
+ }
+
+ for (String arg : args) {
+ if (arg.equals(PROTO_ARG)) {
+ final ProtoOutputStream proto = new ProtoOutputStream(fd);
+ dumpProto(proto);
+ proto.flush();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Write the proto dump for all displays associated with this client.
+ *
+ * @param proto The proto stream to which the dumps are written.
+ * @hide
+ */
+ public static void dumpProto(ProtoOutputStream proto) {
+ for (int i = sInstanceMap.size() - 1; i >= 0; i--) {
+ InputMethodManager imm = sInstanceMap.valueAt(i);
+ imm.dumpDebug(proto);
+ }
+ }
+
+ /**
+ * Write the proto dump of various client side components to the provided
+ * {@link ProtoOutputStream}.
+ *
+ * @param proto The proto stream to which the dumps are written.
+ * @hide
+ */
+ @GuardedBy("mH")
+ public void dumpDebug(ProtoOutputStream proto) {
+ if (mCurMethod == null) {
+ return;
+ }
+
+ final long clientDumpToken = proto.start(CLIENT);
+ proto.write(DISPLAY_ID, mDisplayId);
+ final long token = proto.start(INPUT_METHOD_MANAGER);
+ synchronized (mH) {
+ proto.write(CUR_ID, mCurId);
+ proto.write(FULLSCREEN_MODE, mFullscreenMode);
+ proto.write(ACTIVE, mActive);
+ proto.write(SERVED_CONNECTING, mServedConnecting);
+ proto.end(token);
+ if (mCurRootView != null) {
+ mCurRootView.dumpDebug(proto, VIEW_ROOT_IMPL);
+ }
+ if (mCurrentTextBoxAttribute != null) {
+ mCurrentTextBoxAttribute.dumpDebug(proto, EDITOR_INFO);
+ }
+ if (mImeInsetsConsumer != null) {
+ mImeInsetsConsumer.dumpDebug(proto, IME_INSETS_SOURCE_CONSUMER);
+ }
+ }
+ proto.end(clientDumpToken);
+ }
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 60f8bb7ebe6c..fa195211fb54 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -16,6 +16,8 @@
package android.widget;
+import static android.view.OnReceiveContentCallback.Payload.SOURCE_DRAG_AND_DROP;
+
import android.R;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
@@ -96,6 +98,7 @@ import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
+import android.view.OnReceiveContentCallback;
import android.view.SubMenu;
import android.view.View;
import android.view.View.DragShadowBuilder;
@@ -2851,9 +2854,11 @@ public class Editor {
try {
final int originalLength = mTextView.getText().length();
Selection.setSelection((Spannable) mTextView.getText(), offset);
- ClipData clip = event.getClipData();
- mTextView.getRichContentReceiver().onReceive(mTextView, clip,
- RichContentReceiver.SOURCE_DRAG_AND_DROP, 0);
+ final ClipData clip = event.getClipData();
+ final OnReceiveContentCallback.Payload payload =
+ new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_DRAG_AND_DROP)
+ .build();
+ mTextView.onReceiveContent(payload);
if (dragDropIntoItself) {
deleteSourceAfterLocalDrop(dragLocalState, offset, originalLength);
}
diff --git a/core/java/android/widget/RichContentReceiver.java b/core/java/android/widget/RichContentReceiver.java
deleted file mode 100644
index 80a05622aa67..000000000000
--- a/core/java/android/widget/RichContentReceiver.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.widget;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.SuppressLint;
-import android.content.ClipData;
-import android.content.ClipDescription;
-import android.view.View;
-import android.view.inputmethod.InputConnection;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Set;
-
-/**
- * Callback for apps to implement handling for insertion of rich content. "Rich content" here refers
- * to both text and non-text content: plain text, styled text, HTML, images, videos, audio files,
- * etc.
- *
- * <p>This callback can be attached to different types of UI components. For editable
- * {@link TextView} components, implementations should typically wrap
- * {@link TextView#DEFAULT_RICH_CONTENT_RECEIVER}.
- *
- * <p>Example implementation:<br>
- * <pre class="prettyprint">
- * public class MyRichContentReceiver implements RichContentReceiver&lt;TextView&gt; {
- *
- * private static final Set&lt;String&gt; SUPPORTED_MIME_TYPES = Collections.unmodifiableSet(
- * Set.of("text/*", "image/gif", "image/png", "image/jpg"));
- *
- * &#64;NonNull
- * &#64;Override
- * public Set&lt;String&gt; getSupportedMimeTypes() {
- * return SUPPORTED_MIME_TYPES;
- * }
- *
- * &#64;Override
- * public boolean onReceive(@NonNull TextView textView, @NonNull ClipData clip,
- * int source, int flags) {
- * if (clip.getDescription().hasMimeType("image/*")) {
- * return receiveImage(textView, clip);
- * }
- * return TextView.DEFAULT_RICH_CONTENT_RECEIVER.onReceive(textView, clip, source);
- * }
- *
- * private boolean receiveImage(@NonNull TextView textView, @NonNull ClipData clip) {
- * // ... app-specific logic to handle the content URI in the clip ...
- * }
- * }
- * </pre>
- *
- * @param <T> The type of {@link View} with which this receiver can be associated.
- */
-@SuppressLint("CallbackMethodName")
-public interface RichContentReceiver<T extends View> {
- /**
- * Specifies the UI through which content is being inserted.
- *
- * @hide
- */
- @IntDef(prefix = {"SOURCE_"}, value = {SOURCE_CLIPBOARD, SOURCE_INPUT_METHOD,
- SOURCE_DRAG_AND_DROP, SOURCE_AUTOFILL, SOURCE_PROCESS_TEXT})
- @Retention(RetentionPolicy.SOURCE)
- @interface Source {}
-
- /**
- * Specifies that the operation was triggered by a paste from the clipboard (e.g. "Paste" or
- * "Paste as plain text" action in the insertion/selection menu).
- */
- int SOURCE_CLIPBOARD = 0;
-
- /**
- * Specifies that the operation was triggered from the soft keyboard (also known as input method
- * editor or IME). See https://developer.android.com/guide/topics/text/image-keyboard for more
- * info.
- */
- int SOURCE_INPUT_METHOD = 1;
-
- /**
- * Specifies that the operation was triggered by the drag/drop framework. See
- * https://developer.android.com/guide/topics/ui/drag-drop for more info.
- */
- int SOURCE_DRAG_AND_DROP = 2;
-
- /**
- * Specifies that the operation was triggered by the autofill framework. See
- * https://developer.android.com/guide/topics/text/autofill for more info.
- */
- int SOURCE_AUTOFILL = 3;
-
- /**
- * Specifies that the operation was triggered by a result from a
- * {@link android.content.Intent#ACTION_PROCESS_TEXT PROCESS_TEXT} action in the selection menu.
- */
- int SOURCE_PROCESS_TEXT = 4;
-
- /**
- * Flags to configure the insertion behavior.
- *
- * @hide
- */
- @IntDef(flag = true, prefix = {"FLAG_"}, value = {FLAG_CONVERT_TO_PLAIN_TEXT})
- @Retention(RetentionPolicy.SOURCE)
- @interface Flags {}
-
- /**
- * Flag for {@link #onReceive} requesting that the content should be converted to plain text
- * prior to inserting.
- */
- int FLAG_CONVERT_TO_PLAIN_TEXT = 1 << 0;
-
- /**
- * Insert the given clip.
- *
- * <p>For editable {@link TextView} components, this function will be invoked for the
- * following scenarios:
- * <ol>
- * <li>Paste from the clipboard (e.g. "Paste" or "Paste as plain text" action in the
- * insertion/selection menu)
- * <li>Content insertion from the keyboard ({@link InputConnection#commitContent})
- * <li>Drag and drop ({@link View#onDragEvent})
- * <li>Autofill, when the type for the field is
- * {@link android.view.View.AutofillType#AUTOFILL_TYPE_RICH_CONTENT}
- * </ol>
- *
- * <p>For text, if the view has a selection, the selection should be overwritten by the
- * clip; if there's no selection, this method should insert the content at the current
- * cursor position.
- *
- * <p>For rich content (e.g. an image), this function may insert the content inline, or it may
- * add the content as an attachment (could potentially go into a completely separate view).
- *
- * <p>This function may be invoked with a clip whose MIME type is not in the list of supported
- * types returned by {@link #getSupportedMimeTypes()}. This provides the opportunity to
- * implement custom fallback logic if desired.
- *
- * @param view The view where the content insertion was requested.
- * @param clip The clip to insert.
- * @param source The trigger of the operation.
- * @param flags Optional flags to configure the insertion behavior. Use 0 for default
- * behavior. See {@code FLAG_} constants on this interface for other options.
- * @return Returns true if the clip was inserted.
- */
- boolean onReceive(@NonNull T view, @NonNull ClipData clip, @Source int source, int flags);
-
- /**
- * Returns the MIME types that can be handled by this callback.
- *
- * <p>Different platform features (e.g. pasting from the clipboard, inserting stickers from the
- * keyboard, etc) may use this function to conditionally alter their behavior. For example, the
- * keyboard may choose to hide its UI for inserting GIFs if the input field that has focus has
- * a {@link RichContentReceiver} set and the MIME types returned from this function don't
- * include "image/gif".
- *
- * @return An immutable set with the MIME types supported by this callback. The returned
- * MIME types may contain wildcards such as "text/*", "image/*", etc.
- */
- @NonNull
- Set<String> getSupportedMimeTypes();
-
- /**
- * Returns true if the MIME type of the given clip is {@link #getSupportedMimeTypes supported}
- * by this receiver.
- *
- * @hide
- */
- default boolean supports(@NonNull ClipDescription description) {
- for (String supportedMimeType : getSupportedMimeTypes()) {
- if (description.hasMimeType(supportedMimeType)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns true if this receiver {@link #getSupportedMimeTypes supports} non-text content, such
- * as images.
- *
- * @hide
- */
- default boolean supportsNonTextContent() {
- for (String supportedMimeType : getSupportedMimeTypes()) {
- if (!supportedMimeType.startsWith("text/")) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns the symbolic name of the given source.
- *
- * @hide
- */
- static String sourceToString(@Source int source) {
- switch (source) {
- case SOURCE_CLIPBOARD: return "SOURCE_CLIPBOARD";
- case SOURCE_INPUT_METHOD: return "SOURCE_INPUT_METHOD";
- case SOURCE_DRAG_AND_DROP: return "SOURCE_DRAG_AND_DROP";
- case SOURCE_AUTOFILL: return "SOURCE_AUTOFILL";
- case SOURCE_PROCESS_TEXT: return "SOURCE_PROCESS_TEXT";
- }
- return String.valueOf(source);
- }
-
- /**
- * Returns the symbolic names of the set flags or {@code "0"} if no flags are set.
- *
- * @hide
- */
- static String flagsToString(@Flags int flags) {
- if ((flags & FLAG_CONVERT_TO_PLAIN_TEXT) != 0) {
- return "FLAG_CONVERT_TO_PLAIN_TEXT";
- }
- return String.valueOf(flags);
- }
-}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 6f14dfb89e6b..52a3f4145e7e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,12 +17,15 @@
package android.widget;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.view.OnReceiveContentCallback.Payload.FLAG_CONVERT_TO_PLAIN_TEXT;
+import static android.view.OnReceiveContentCallback.Payload.SOURCE_AUTOFILL;
+import static android.view.OnReceiveContentCallback.Payload.SOURCE_CLIPBOARD;
+import static android.view.OnReceiveContentCallback.Payload.SOURCE_PROCESS_TEXT;
import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_RENDERING_INFO_KEY;
import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH;
import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX;
import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY;
import static android.view.inputmethod.CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION;
-import static android.widget.RichContentReceiver.SOURCE_PROCESS_TEXT;
import android.R;
import android.annotation.CallSuper;
@@ -39,6 +42,7 @@ import android.annotation.RequiresPermission;
import android.annotation.Size;
import android.annotation.StringRes;
import android.annotation.StyleRes;
+import android.annotation.TestApi;
import android.annotation.XmlRes;
import android.app.Activity;
import android.app.PendingIntent;
@@ -149,6 +153,7 @@ import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.OnReceiveContentCallback;
import android.view.PointerIcon;
import android.view.View;
import android.view.ViewConfiguration;
@@ -426,7 +431,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
/**
* @hide
*/
- static final int PROCESS_TEXT_REQUEST_CODE = 100;
+ @TestApi
+ public static final int PROCESS_TEXT_REQUEST_CODE = 100;
/**
* Return code of {@link #doKeyDown}.
@@ -735,6 +741,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private boolean mLocalesChanged = false;
private int mTextSizeUnit = -1;
+ // True if force bold text feature is enabled. This feature makes all text bolder.
+ private boolean mForceBoldTextEnabled;
+ private Typeface mOriginalTypeface;
+
// True if setKeyListener() has been explicitly called
private boolean mListenerChanged = false;
// True if internationalized input should be used for numbers and date and time.
@@ -882,12 +892,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
/**
* The default content insertion callback used by {@link TextView}. See
- * {@link #setRichContentReceiver} for more info.
+ * {@link #setOnReceiveContentCallback} for more info.
*/
- public static final @NonNull RichContentReceiver<TextView> DEFAULT_RICH_CONTENT_RECEIVER =
- TextViewRichContentReceiver.INSTANCE;
-
- private RichContentReceiver<TextView> mRichContentReceiver = DEFAULT_RICH_CONTENT_RECEIVER;
+ private static final TextViewOnReceiveContentCallback DEFAULT_ON_RECEIVE_CONTENT_CALLBACK =
+ new TextViewOnReceiveContentCallback();
private static final int DEVICE_PROVISIONED_UNKNOWN = 0;
private static final int DEVICE_PROVISIONED_NO = 1;
@@ -1645,6 +1653,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
attributes.mTypefaceIndex = MONOSPACE;
}
+ mForceBoldTextEnabled = getContext().getResources().getConfiguration().forceBoldText
+ == Configuration.FORCE_BOLD_TEXT_YES;
applyTextAppearance(attributes);
if (isPassword) {
@@ -2138,15 +2148,20 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
/**
* @hide
*/
+ @TestApi
@Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (requestCode == PROCESS_TEXT_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK && data != null) {
CharSequence result = data.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEXT);
if (result != null) {
if (isTextEditable()) {
ClipData clip = ClipData.newPlainText("", result);
- mRichContentReceiver.onReceive(this, clip, SOURCE_PROCESS_TEXT, 0);
+ OnReceiveContentCallback.Payload payload =
+ new OnReceiveContentCallback.Payload.Builder(
+ clip, SOURCE_PROCESS_TEXT)
+ .build();
+ onReceiveContent(payload);
if (mEditor != null) {
mEditor.refreshTextActionMode();
}
@@ -4267,6 +4282,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
invalidate();
}
}
+ if (newConfig.forceBoldText == Configuration.FORCE_BOLD_TEXT_YES) {
+ mForceBoldTextEnabled = true;
+ setTypeface(getTypeface());
+ } else if (newConfig.forceBoldText == Configuration.FORCE_BOLD_TEXT_NO
+ || newConfig.forceBoldText == Configuration.FORCE_BOLD_TEXT_UNDEFINED) {
+ mForceBoldTextEnabled = false;
+ setTypeface(getTypeface());
+ }
}
/**
@@ -4418,6 +4441,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @attr ref android.R.styleable#TextView_textStyle
*/
public void setTypeface(@Nullable Typeface tf) {
+ mOriginalTypeface = tf;
+ if (mForceBoldTextEnabled) {
+ int newWeight = tf != null ? tf.getWeight() + 300 : 400;
+ newWeight = Math.min(newWeight, 1000);
+ int typefaceStyle = tf != null ? tf.getStyle() : 0;
+ boolean italic = (typefaceStyle & Typeface.ITALIC) != 0;
+ tf = Typeface.create(tf, newWeight, italic);
+ }
if (mTextPaint.getTypeface() != tf) {
mTextPaint.setTypeface(tf);
@@ -4441,7 +4472,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
@InspectableProperty
public Typeface getTypeface() {
- return mTextPaint.getTypeface();
+ return mOriginalTypeface;
}
/**
@@ -8722,9 +8753,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
outAttrs.initialSelEnd = getSelectionEnd();
outAttrs.initialCapsMode = ic.getCursorCapsMode(getInputType());
outAttrs.setInitialSurroundingText(mText);
- int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
- if (targetSdkVersion > Build.VERSION_CODES.R) {
- outAttrs.contentMimeTypes = mRichContentReceiver.getSupportedMimeTypes()
+ // If a custom `OnReceiveContentCallback` is set, pass its supported MIME types.
+ OnReceiveContentCallback<TextView> receiver = getOnReceiveContentCallback();
+ if (receiver != null) {
+ outAttrs.contentMimeTypes = receiver.getSupportedMimeTypes(this)
.toArray(new String[0]);
}
return ic;
@@ -11827,7 +11859,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
Log.w(LOG_TAG, "cannot autofill non-editable TextView: " + this);
return;
}
- ClipData clip;
+ final ClipData clip;
if (value.isRichContent()) {
clip = value.getRichContentValue();
} else if (value.isText()) {
@@ -11837,22 +11869,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
+ " cannot be autofilled into " + this);
return;
}
- mRichContentReceiver.onReceive(this, clip, RichContentReceiver.SOURCE_AUTOFILL, 0);
+ final OnReceiveContentCallback.Payload payload =
+ new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_AUTOFILL).build();
+ onReceiveContent(payload);
}
@Override
public @AutofillType int getAutofillType() {
- if (!isTextEditable()) {
- return AUTOFILL_TYPE_NONE;
- }
- final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
- if (targetSdkVersion <= Build.VERSION_CODES.R) {
- return AUTOFILL_TYPE_TEXT;
- }
- // TODO(b/147301047): Update autofill framework code to check the target SDK of the autofill
- // provider and force the type AUTOFILL_TYPE_TEXT for providers that target older SDKs.
- return mRichContentReceiver.supportsNonTextContent() ? AUTOFILL_TYPE_RICH_CONTENT
- : AUTOFILL_TYPE_TEXT;
+ return isTextEditable() ? AUTOFILL_TYPE_TEXT : AUTOFILL_TYPE_NONE;
}
/**
@@ -12913,8 +12937,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (clip == null) {
return;
}
- int flags = withFormatting ? 0 : RichContentReceiver.FLAG_CONVERT_TO_PLAIN_TEXT;
- mRichContentReceiver.onReceive(this, clip, RichContentReceiver.SOURCE_CLIPBOARD, flags);
+ final OnReceiveContentCallback.Payload payload =
+ new OnReceiveContentCallback.Payload.Builder(clip, SOURCE_CLIPBOARD)
+ .setFlags(withFormatting ? 0 : FLAG_CONVERT_TO_PLAIN_TEXT)
+ .build();
+ onReceiveContent(payload);
sLastCutCopyOrTextChangedTime = 0;
}
@@ -13697,43 +13724,58 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
- * Returns the callback that handles insertion of content into this view (e.g. pasting from
- * the clipboard). See {@link #setRichContentReceiver} for more info.
+ * Returns the callback used for handling insertion of content into this view. See
+ * {@link #setOnReceiveContentCallback} for more info.
*
- * @return The callback that this view is using to handle insertion of content. Returns
- * {@link #DEFAULT_RICH_CONTENT_RECEIVER} if no custom callback has been
- * {@link #setRichContentReceiver set}.
+ * @return The callback for handling insertion of content. Returns null if no callback has been
+ * {@link #setOnReceiveContentCallback set}.
*/
- @NonNull
- public RichContentReceiver<TextView> getRichContentReceiver() {
- return mRichContentReceiver;
+ @SuppressWarnings("unchecked")
+ @Nullable
+ @Override
+ public OnReceiveContentCallback<TextView> getOnReceiveContentCallback() {
+ return (OnReceiveContentCallback<TextView>) super.getOnReceiveContentCallback();
}
/**
* Sets the callback to handle insertion of content into this view.
*
- * <p>"Content" and "rich content" here refers to both text and non-text: plain text, styled
- * text, HTML, images, videos, audio files, etc.
- *
- * <p>The callback configured here should typically wrap {@link #DEFAULT_RICH_CONTENT_RECEIVER}
- * to provide consistent behavior for text content.
- *
* <p>This callback will be invoked for the following scenarios:
* <ol>
* <li>Paste from the clipboard (e.g. "Paste" or "Paste as plain text" action in the
* insertion/selection menu)
- * <li>Content insertion from the keyboard ({@link InputConnection#commitContent})
- * <li>Drag and drop ({@link View#onDragEvent})
- * <li>Autofill, when the type for the field is
- * {@link android.view.View.AutofillType#AUTOFILL_TYPE_RICH_CONTENT}
+ * <li>Content insertion from the keyboard (from {@link InputConnection#commitContent})
+ * <li>Drag and drop (drop events from {@link #onDragEvent(DragEvent)})
+ * <li>Autofill (from {@link #autofill(AutofillValue)})
+ * <li>{@link Intent#ACTION_PROCESS_TEXT} replacement
* </ol>
*
- * @param receiver The callback to use. This can be {@link #DEFAULT_RICH_CONTENT_RECEIVER} to
- * reset to the default behavior.
+ * <p>The callback will only be invoked if the MIME type of the content is
+ * {@link OnReceiveContentCallback#getSupportedMimeTypes declared as supported} by the callback.
+ * If the content type is not supported by the callback, the default platform handling will be
+ * executed instead.
+ *
+ * @param callback The callback to use. This can be null to reset to the default behavior.
*/
- public void setRichContentReceiver(@NonNull RichContentReceiver<TextView> receiver) {
- mRichContentReceiver = Objects.requireNonNull(receiver,
- "RichContentReceiver should not be null.");
+ @Override
+ public void setOnReceiveContentCallback(
+ @Nullable OnReceiveContentCallback<? extends View> callback) {
+ super.setOnReceiveContentCallback(callback);
+ }
+
+ /**
+ * Handles the request to insert content using the configured callback or the default callback.
+ *
+ * @hide
+ */
+ void onReceiveContent(@NonNull OnReceiveContentCallback.Payload payload) {
+ OnReceiveContentCallback<TextView> receiver = getOnReceiveContentCallback();
+ ClipDescription description = payload.getClip().getDescription();
+ if (receiver != null && receiver.supports(this, description)) {
+ receiver.onReceiveContent(this, payload);
+ } else {
+ DEFAULT_ON_RECEIVE_CONTENT_CALLBACK.onReceiveContent(this, payload);
+ }
}
private static void logCursor(String location, @Nullable String msgFormat, Object ... msgArgs) {
diff --git a/core/java/android/widget/TextViewRichContentReceiver.java b/core/java/android/widget/TextViewOnReceiveContentCallback.java
index 4f2d95466997..35618cb3d2a5 100644
--- a/core/java/android/widget/TextViewRichContentReceiver.java
+++ b/core/java/android/widget/TextViewOnReceiveContentCallback.java
@@ -16,7 +16,12 @@
package android.widget;
+import static android.view.OnReceiveContentCallback.Payload.FLAG_CONVERT_TO_PLAIN_TEXT;
+import static android.view.OnReceiveContentCallback.Payload.SOURCE_AUTOFILL;
+import static android.view.OnReceiveContentCallback.Payload.SOURCE_DRAG_AND_DROP;
+
import android.annotation.NonNull;
+import android.annotation.SuppressLint;
import android.content.ClipData;
import android.content.Context;
import android.text.Editable;
@@ -24,54 +29,45 @@ import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.util.Log;
+import android.view.OnReceiveContentCallback;
+import android.view.OnReceiveContentCallback.Payload.Flags;
+import android.view.OnReceiveContentCallback.Payload.Source;
import java.util.Collections;
import java.util.Set;
/**
- * Default implementation of {@link RichContentReceiver} for editable {@link TextView} components.
- * This class handles insertion of text (plain text, styled text, HTML, etc) but not images or other
- * rich content. Typically this class will be used as a delegate by custom implementations of
- * {@link RichContentReceiver}, to provide consistent behavior for insertion of text while
- * implementing custom behavior for insertion of other content (images, etc). See
- * {@link TextView#DEFAULT_RICH_CONTENT_RECEIVER}.
- *
- * @hide
+ * Default implementation of {@link android.view.OnReceiveContentCallback} for editable
+ * {@link TextView} components. This class handles insertion of text (plain text, styled text, HTML,
+ * etc) but not images or other content. This class can be used as a base class for an
+ * implementation of {@link android.view.OnReceiveContentCallback} for a {@link TextView}, to
+ * provide consistent behavior for insertion of text.
*/
-final class TextViewRichContentReceiver implements RichContentReceiver<TextView> {
- static final TextViewRichContentReceiver INSTANCE = new TextViewRichContentReceiver();
-
- private static final String LOG_TAG = "RichContentReceiver";
+public class TextViewOnReceiveContentCallback implements OnReceiveContentCallback<TextView> {
+ private static final String LOG_TAG = "OnReceiveContent";
private static final Set<String> MIME_TYPES_ALL_TEXT = Collections.singleton("text/*");
+ @SuppressLint("CallbackMethodName")
+ @NonNull
@Override
- public Set<String> getSupportedMimeTypes() {
+ public Set<String> getSupportedMimeTypes(@NonNull TextView view) {
return MIME_TYPES_ALL_TEXT;
}
@Override
- public boolean onReceive(@NonNull TextView textView, @NonNull ClipData clip,
- @Source int source, @Flags int flags) {
+ public boolean onReceiveContent(@NonNull TextView view, @NonNull Payload payload) {
if (Log.isLoggable(LOG_TAG, Log.DEBUG)) {
- StringBuilder sb = new StringBuilder("onReceive: clip=");
- if (clip.getDescription() == null) {
- sb.append("null");
- } else {
- clip.getDescription().toShortStringTypesOnly(sb);
- }
- sb.append(", source=").append(RichContentReceiver.sourceToString(source));
- sb.append(", flags=").append(RichContentReceiver.flagsToString(flags));
- Log.d(LOG_TAG, sb.toString());
+ Log.d(LOG_TAG, "onReceive:" + payload);
}
+ ClipData clip = payload.getClip();
+ @Source int source = payload.getSource();
+ @Flags int flags = payload.getFlags();
if (source == SOURCE_AUTOFILL) {
- return onReceiveForAutofill(textView, clip, flags);
+ return onReceiveForAutofill(view, clip, flags);
}
if (source == SOURCE_DRAG_AND_DROP) {
- return onReceiveForDragAndDrop(textView, clip, flags);
- }
- if (source == SOURCE_INPUT_METHOD && !supports(clip.getDescription())) {
- return false;
+ return onReceiveForDragAndDrop(view, clip, flags);
}
// The code here follows the original paste logic from TextView:
@@ -79,8 +75,8 @@ final class TextViewRichContentReceiver implements RichContentReceiver<TextView>
// In particular, multiple items within the given ClipData will trigger separate calls to
// replace/insert. This is to preserve the original behavior with respect to TextWatcher
// notifications fired from SpannableStringBuilder when replace/insert is called.
- final Editable editable = (Editable) textView.getText();
- final Context context = textView.getContext();
+ final Editable editable = (Editable) view.getText();
+ final Context context = view.getContext();
boolean didFirst = false;
for (int i = 0; i < clip.getItemCount(); i++) {
CharSequence itemText;
@@ -100,7 +96,7 @@ final class TextViewRichContentReceiver implements RichContentReceiver<TextView>
}
}
}
- return didFirst;
+ return true;
}
private static void replaceSelection(@NonNull Editable editable,
@@ -128,7 +124,7 @@ final class TextViewRichContentReceiver implements RichContentReceiver<TextView>
@NonNull ClipData clip, @Flags int flags) {
final CharSequence text = coerceToText(clip, textView.getContext(), flags);
if (text.length() == 0) {
- return false;
+ return true;
}
replaceSelection((Editable) textView.getText(), text);
return true;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 944f2ecdd647..61a625e40dcd 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -1771,7 +1771,7 @@ public class ChooserActivity extends ResolverActivity implements
case ChooserListAdapter.TARGET_CALLER:
case ChooserListAdapter.TARGET_STANDARD:
cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET;
- value -= currentListAdapter.getSelectableServiceTargetCount();
+ value -= currentListAdapter.getSurfacedTargetInfo().size();
numCallerProvided = currentListAdapter.getCallerTargetCount();
getChooserActivityLogger().logShareTargetSelected(
SELECTION_TYPE_APP,
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 4a0e26a5c7cb..308af99d465a 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -145,7 +145,7 @@ public class BatteryStatsImpl extends BatteryStats {
private static final boolean DEBUG = false;
public static final boolean DEBUG_ENERGY = false;
private static final boolean DEBUG_ENERGY_CPU = DEBUG_ENERGY;
- private static final boolean DEBUG_BINDER_STATS = true;
+ private static final boolean DEBUG_BINDER_STATS = false;
private static final boolean DEBUG_MEMORY = false;
private static final boolean DEBUG_HISTORY = false;
private static final boolean USE_OLD_HISTORY = false; // for debugging.
@@ -156,7 +156,7 @@ public class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- static final int VERSION = 188 + (USE_OLD_HISTORY ? 1000 : 0);
+ static final int VERSION = 189 + (USE_OLD_HISTORY ? 1000 : 0);
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -221,7 +221,8 @@ public class BatteryStatsImpl extends BatteryStats {
@VisibleForTesting
protected KernelSingleUidTimeReader mKernelSingleUidTimeReader;
@VisibleForTesting
- protected SystemServerCpuThreadReader mSystemServerCpuThreadReader;
+ protected SystemServerCpuThreadReader mSystemServerCpuThreadReader =
+ SystemServerCpuThreadReader.create();
private final KernelMemoryBandwidthStats mKernelMemoryBandwidthStats
= new KernelMemoryBandwidthStats();
@@ -1014,14 +1015,21 @@ public class BatteryStatsImpl extends BatteryStats {
private long[] mCpuFreqs;
/**
+ * Times spent by the system server process grouped by cluster and CPU speed.
+ */
+ private LongSamplingCounterArray mSystemServerCpuTimesUs;
+
+ private long[] mTmpSystemServerCpuTimesUs;
+
+ /**
* Times spent by the system server threads grouped by cluster and CPU speed.
*/
- private LongSamplingCounter[][] mSystemServerThreadCpuTimesUs;
+ private LongSamplingCounterArray mSystemServerThreadCpuTimesUs;
/**
* Times spent by the system server threads handling incoming binder requests.
*/
- private LongSamplingCounter[][] mBinderThreadCpuTimesUs;
+ private LongSamplingCounterArray mBinderThreadCpuTimesUs;
@VisibleForTesting
protected PowerProfile mPowerProfile;
@@ -10610,8 +10618,6 @@ public class BatteryStatsImpl extends BatteryStats {
firstCpuOfCluster += mPowerProfile.getNumCoresInCpuCluster(i);
}
- mSystemServerCpuThreadReader = SystemServerCpuThreadReader.create();
-
if (mEstimatedBatteryCapacity == -1) {
// Initialize the estimated battery capacity to a known preset one.
mEstimatedBatteryCapacity = (int) mPowerProfile.getBatteryCapacity();
@@ -11291,6 +11297,7 @@ public class BatteryStatsImpl extends BatteryStats {
mTmpRailStats.reset();
+ resetIfNotNull(mSystemServerCpuTimesUs, false, elapsedRealtimeUs);
resetIfNotNull(mSystemServerThreadCpuTimesUs, false, elapsedRealtimeUs);
resetIfNotNull(mBinderThreadCpuTimesUs, false, elapsedRealtimeUs);
@@ -12421,38 +12428,58 @@ public class BatteryStatsImpl extends BatteryStats {
SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
mSystemServerCpuThreadReader.readDelta();
+ if (systemServiceCpuThreadTimes == null) {
+ return;
+ }
- int index = 0;
int numCpuClusters = mPowerProfile.getNumCpuClusters();
- if (mSystemServerThreadCpuTimesUs == null) {
- mSystemServerThreadCpuTimesUs = new LongSamplingCounter[numCpuClusters][];
- mBinderThreadCpuTimesUs = new LongSamplingCounter[numCpuClusters][];
- }
- for (int cluster = 0; cluster < numCpuClusters; cluster++) {
- int numSpeeds = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
- if (mSystemServerThreadCpuTimesUs[cluster] == null) {
- mSystemServerThreadCpuTimesUs[cluster] = new LongSamplingCounter[numSpeeds];
- mBinderThreadCpuTimesUs[cluster] = new LongSamplingCounter[numSpeeds];
- for (int speed = 0; speed < numSpeeds; speed++) {
- mSystemServerThreadCpuTimesUs[cluster][speed] =
- new LongSamplingCounter(mOnBatteryTimeBase);
- mBinderThreadCpuTimesUs[cluster][speed] =
- new LongSamplingCounter(mOnBatteryTimeBase);
- }
- }
- for (int speed = 0; speed < numSpeeds; speed++) {
- mSystemServerThreadCpuTimesUs[cluster][speed].addCountLocked(
- systemServiceCpuThreadTimes.threadCpuTimesUs[index]);
- mBinderThreadCpuTimesUs[cluster][speed].addCountLocked(
- systemServiceCpuThreadTimes.binderThreadCpuTimesUs[index]);
- index++;
- }
+ if (mSystemServerCpuTimesUs == null) {
+ mSystemServerCpuTimesUs = new LongSamplingCounterArray(mOnBatteryTimeBase);
+ mSystemServerThreadCpuTimesUs = new LongSamplingCounterArray(mOnBatteryTimeBase);
+ mBinderThreadCpuTimesUs = new LongSamplingCounterArray(mOnBatteryTimeBase);
+ }
+ mSystemServerThreadCpuTimesUs.addCountLocked(systemServiceCpuThreadTimes.threadCpuTimesUs);
+ mBinderThreadCpuTimesUs.addCountLocked(systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
+
+ long totalCpuTimeAllThreads = 0;
+ for (int index = systemServiceCpuThreadTimes.threadCpuTimesUs.length - 1; index >= 0;
+ index--) {
+ totalCpuTimeAllThreads += systemServiceCpuThreadTimes.threadCpuTimesUs[index];
+ }
+
+ // Estimate per cluster per frequency CPU time for the entire process
+ // by distributing the total process CPU time proportionately to how much
+ // CPU time its threads took on those clusters/frequencies. This algorithm
+ // works more accurately when when we have equally distributed concurrency.
+ // TODO(b/169279846): obtain actual process CPU times from the kernel
+ long processCpuTime = systemServiceCpuThreadTimes.processCpuTimeUs;
+ if (mTmpSystemServerCpuTimesUs == null) {
+ mTmpSystemServerCpuTimesUs =
+ new long[systemServiceCpuThreadTimes.threadCpuTimesUs.length];
}
+ for (int index = systemServiceCpuThreadTimes.threadCpuTimesUs.length - 1; index >= 0;
+ index--) {
+ mTmpSystemServerCpuTimesUs[index] =
+ processCpuTime * systemServiceCpuThreadTimes.threadCpuTimesUs[index]
+ / totalCpuTimeAllThreads;
+
+ }
+
+ mSystemServerCpuTimesUs.addCountLocked(mTmpSystemServerCpuTimesUs);
+
if (DEBUG_BINDER_STATS) {
Slog.d(TAG, "System server threads per CPU cluster (binder threads/total threads/%)");
- long binderThreadTimeMs = 0;
+ long totalCpuTimeMs = 0;
long totalThreadTimeMs = 0;
+ long binderThreadTimeMs = 0;
int cpuIndex = 0;
+ final long[] systemServerCpuTimesUs =
+ mSystemServerCpuTimesUs.getCountsLocked(0);
+ final long[] systemServerThreadCpuTimesUs =
+ mSystemServerThreadCpuTimesUs.getCountsLocked(0);
+ final long[] binderThreadCpuTimesUs =
+ mBinderThreadCpuTimesUs.getCountsLocked(0);
+ int index = 0;
for (int cluster = 0; cluster < numCpuClusters; cluster++) {
StringBuilder sb = new StringBuilder();
sb.append("cpu").append(cpuIndex).append(": [");
@@ -12461,15 +12488,14 @@ public class BatteryStatsImpl extends BatteryStats {
if (speed != 0) {
sb.append(", ");
}
- long totalCountMs =
- mSystemServerThreadCpuTimesUs[cluster][speed].getCountLocked(0) / 1000;
- long binderCountMs = mBinderThreadCpuTimesUs[cluster][speed].getCountLocked(0)
- / 1000;
+ long totalCountMs = systemServerThreadCpuTimesUs[index] / 1000;
+ long binderCountMs = binderThreadCpuTimesUs[index] / 1000;
sb.append(String.format("%d/%d(%.1f%%)",
binderCountMs,
totalCountMs,
totalCountMs != 0 ? (double) binderCountMs * 100 / totalCountMs : 0));
+ totalCpuTimeMs += systemServerCpuTimesUs[index] / 1000;
totalThreadTimeMs += totalCountMs;
binderThreadTimeMs += binderCountMs;
index++;
@@ -12477,6 +12503,8 @@ public class BatteryStatsImpl extends BatteryStats {
cpuIndex += mPowerProfile.getNumCoresInCpuCluster(cluster);
Slog.d(TAG, sb.toString());
}
+
+ Slog.d(TAG, "Total system server CPU time (ms): " + totalCpuTimeMs);
Slog.d(TAG, "Total system server thread time (ms): " + totalThreadTimeMs);
Slog.d(TAG, String.format("Total Binder thread time (ms): %d (%.1f%%)",
binderThreadTimeMs,
@@ -13715,7 +13743,7 @@ public class BatteryStatsImpl extends BatteryStats {
@Override
- public long getSystemServiceTimeAtCpuSpeed(int cluster, int step) {
+ public long[] getSystemServiceTimeAtCpuSpeeds() {
// Estimates the time spent by the system server handling incoming binder requests.
//
// The data that we can get from the kernel is this:
@@ -13731,7 +13759,7 @@ public class BatteryStatsImpl extends BatteryStats {
// - These 10 threads spent 1000 ms of CPU time in aggregate
// - Of the 10 threads 4 were execute exclusively incoming binder calls.
// - These 4 "binder" threads consumed 600 ms of CPU time in aggregate
- // - The real time spent by the system server UID doing all of this is, say, 200 ms.
+ // - The real time spent by the system server process doing all of this is, say, 200 ms.
//
// We will assume that power consumption is proportional to the time spent by the CPU
// across all threads. This is a crude assumption, but we don't have more detailed data.
@@ -13745,41 +13773,29 @@ public class BatteryStatsImpl extends BatteryStats {
// of the total power consumed by incoming binder calls for the given cluster/speed
// combination.
- if (mSystemServerThreadCpuTimesUs == null) {
- return 0;
- }
-
- if (cluster < 0 || cluster >= mSystemServerThreadCpuTimesUs.length) {
- return 0;
- }
-
- final LongSamplingCounter[] threadTimesForCluster = mSystemServerThreadCpuTimesUs[cluster];
-
- if (step < 0 || step >= threadTimesForCluster.length) {
- return 0;
- }
-
- Uid systemUid = mUidStats.get(Process.SYSTEM_UID);
- if (systemUid == null) {
- return 0;
+ if (mSystemServerCpuTimesUs == null) {
+ return null;
}
- final long uidTimeAtCpuSpeedUs = systemUid.getTimeAtCpuSpeed(cluster, step,
+ final long[] systemServerCpuTimesUs = mSystemServerCpuTimesUs.getCountsLocked(
+ BatteryStats.STATS_SINCE_CHARGED);
+ final long [] systemServerThreadCpuTimesUs = mSystemServerThreadCpuTimesUs.getCountsLocked(
+ BatteryStats.STATS_SINCE_CHARGED);
+ final long[] binderThreadCpuTimesUs = mBinderThreadCpuTimesUs.getCountsLocked(
BatteryStats.STATS_SINCE_CHARGED);
- if (uidTimeAtCpuSpeedUs == 0) {
- return 0;
- }
- final long uidThreadTimeUs =
- threadTimesForCluster[step].getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
+ final int size = systemServerCpuTimesUs.length;
+ final long[] results = new long[size];
- if (uidThreadTimeUs == 0) {
- return 0;
- }
+ for (int i = 0; i < size; i++) {
+ if (systemServerThreadCpuTimesUs[i] == 0) {
+ continue;
+ }
- final long binderThreadTimeUs = mBinderThreadCpuTimesUs[cluster][step].getCountLocked(
- BatteryStats.STATS_SINCE_CHARGED);
- return uidTimeAtCpuSpeedUs * binderThreadTimeUs / uidThreadTimeUs;
+ results[i] = systemServerCpuTimesUs[i] * binderThreadCpuTimesUs[i]
+ / systemServerThreadCpuTimesUs[i];
+ }
+ return results;
}
/**
@@ -14181,18 +14197,14 @@ public class BatteryStatsImpl extends BatteryStats {
updateSystemServiceCallStats();
if (mSystemServerThreadCpuTimesUs != null) {
pw.println("Per UID System server binder time in ms:");
+ long[] systemServiceTimeAtCpuSpeeds = getSystemServiceTimeAtCpuSpeeds();
for (int i = 0; i < size; i++) {
int u = mUidStats.keyAt(i);
Uid uid = mUidStats.get(u);
double proportionalSystemServiceUsage = uid.getProportionalSystemServiceUsage();
-
long timeUs = 0;
- for (int cluster = 0; cluster < mSystemServerThreadCpuTimesUs.length; cluster++) {
- int numSpeeds = mSystemServerThreadCpuTimesUs[cluster].length;
- for (int speed = 0; speed < numSpeeds; speed++) {
- timeUs += getSystemServiceTimeAtCpuSpeed(cluster, speed)
- * proportionalSystemServiceUsage;
- }
+ for (int j = systemServiceTimeAtCpuSpeeds.length - 1; j >= 0; j--) {
+ timeUs += systemServiceTimeAtCpuSpeeds[j] * proportionalSystemServiceUsage;
}
pw.print(" ");
@@ -15728,8 +15740,10 @@ public class BatteryStatsImpl extends BatteryStats {
mUidStats.append(uid, u);
}
- mSystemServerThreadCpuTimesUs = readCpuSpeedCountersFromParcel(in);
- mBinderThreadCpuTimesUs = readCpuSpeedCountersFromParcel(in);
+ mSystemServerCpuTimesUs = LongSamplingCounterArray.readFromParcel(in, mOnBatteryTimeBase);
+ mSystemServerThreadCpuTimesUs = LongSamplingCounterArray.readFromParcel(in,
+ mOnBatteryTimeBase);
+ mBinderThreadCpuTimesUs = LongSamplingCounterArray.readFromParcel(in, mOnBatteryTimeBase);
}
public void writeToParcel(Parcel out, int flags) {
@@ -15778,7 +15792,7 @@ public class BatteryStatsImpl extends BatteryStats {
mScreenOnTimer.writeToParcel(out, uSecRealtime);
mScreenDozeTimer.writeToParcel(out, uSecRealtime);
- for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
+ for (int i = 0; i < NUM_SCREEN_BRIGHTNESS_BINS; i++) {
mScreenBrightnessTimer[i].writeToParcel(out, uSecRealtime);
}
mInteractiveTimer.writeToParcel(out, uSecRealtime);
@@ -15794,7 +15808,7 @@ public class BatteryStatsImpl extends BatteryStats {
mPhoneSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
}
mPhoneSignalScanningTimer.writeToParcel(out, uSecRealtime);
- for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
+ for (int i = 0; i < NUM_DATA_CONNECTION_TYPES; i++) {
mPhoneDataConnectionsTimer[i].writeToParcel(out, uSecRealtime);
}
for (int i = 0; i < NUM_NETWORK_ACTIVITY_TYPES; i++) {
@@ -15809,18 +15823,18 @@ public class BatteryStatsImpl extends BatteryStats {
mWifiMulticastWakelockTimer.writeToParcel(out, uSecRealtime);
mWifiOnTimer.writeToParcel(out, uSecRealtime);
mGlobalWifiRunningTimer.writeToParcel(out, uSecRealtime);
- for (int i=0; i<NUM_WIFI_STATES; i++) {
+ for (int i = 0; i < NUM_WIFI_STATES; i++) {
mWifiStateTimer[i].writeToParcel(out, uSecRealtime);
}
- for (int i=0; i<NUM_WIFI_SUPPL_STATES; i++) {
+ for (int i = 0; i < NUM_WIFI_SUPPL_STATES; i++) {
mWifiSupplStateTimer[i].writeToParcel(out, uSecRealtime);
}
- for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
+ for (int i = 0; i < NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
mWifiSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
}
mWifiActiveTimer.writeToParcel(out, uSecRealtime);
mWifiActivity.writeToParcel(out, 0);
- for (int i=0; i< GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
+ for (int i = 0; i < GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
mGpsSignalQualityTimer[i].writeToParcel(out, uSecRealtime);
}
mBluetoothActivity.writeToParcel(out, 0);
@@ -15930,8 +15944,9 @@ public class BatteryStatsImpl extends BatteryStats {
} else {
out.writeInt(0);
}
- writeCpuSpeedCountersToParcel(out, mSystemServerThreadCpuTimesUs);
- writeCpuSpeedCountersToParcel(out, mBinderThreadCpuTimesUs);
+ LongSamplingCounterArray.writeToParcel(out, mSystemServerCpuTimesUs);
+ LongSamplingCounterArray.writeToParcel(out, mSystemServerThreadCpuTimesUs);
+ LongSamplingCounterArray.writeToParcel(out, mBinderThreadCpuTimesUs);
}
private void writeCpuSpeedCountersToParcel(Parcel out, LongSamplingCounter[][] counters) {
diff --git a/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java b/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java
new file mode 100644
index 000000000000..0578b8976037
--- /dev/null
+++ b/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static android.os.Process.PROC_OUT_LONG;
+import static android.os.Process.PROC_SPACE_TERM;
+
+import android.annotation.Nullable;
+import android.os.Process;
+import android.system.Os;
+import android.system.OsConstants;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.IOException;
+import java.nio.file.DirectoryIteratorException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Iterates over all threads owned by a given process, and return the CPU usage for
+ * each thread. The CPU usage statistics contain the amount of time spent in a frequency band. CPU
+ * usage is collected using {@link ProcTimeInStateReader}.
+ */
+public class KernelSingleProcessCpuThreadReader {
+
+ private static final String TAG = "KernelSingleProcCpuThreadRdr";
+
+ private static final boolean DEBUG = false;
+
+ /**
+ * The name of the file to read CPU statistics from, must be found in {@code
+ * /proc/$PID/task/$TID}
+ */
+ private static final String CPU_STATISTICS_FILENAME = "time_in_state";
+
+ private static final String PROC_STAT_FILENAME = "stat";
+
+ /** Directory under /proc/$PID containing CPU stats files for threads */
+ public static final String THREAD_CPU_STATS_DIRECTORY = "task";
+
+ /** Default mount location of the {@code proc} filesystem */
+ private static final Path DEFAULT_PROC_PATH = Paths.get("/proc");
+
+ /** The initial {@code time_in_state} file for {@link ProcTimeInStateReader} */
+ private static final Path INITIAL_TIME_IN_STATE_PATH = Paths.get("self/time_in_state");
+
+ /** See https://man7.org/linux/man-pages/man5/proc.5.html */
+ private static final int[] PROCESS_FULL_STATS_FORMAT = new int[]{
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM | PROC_OUT_LONG, // 14: utime
+ PROC_SPACE_TERM | PROC_OUT_LONG, // 15: stime
+ // Ignore remaining fields
+ };
+
+ private final long[] mProcessFullStatsData = new long[2];
+
+ private static final int PROCESS_FULL_STAT_UTIME = 0;
+ private static final int PROCESS_FULL_STAT_STIME = 1;
+
+ /** Used to read and parse {@code time_in_state} files */
+ private final ProcTimeInStateReader mProcTimeInStateReader;
+
+ private final int mPid;
+
+ /** Where the proc filesystem is mounted */
+ private final Path mProcPath;
+
+ // How long a CPU jiffy is in milliseconds.
+ private final long mJiffyMillis;
+
+ // Path: /proc/<pid>/stat
+ private final String mProcessStatFilePath;
+
+ // Path: /proc/<pid>/task
+ private final Path mThreadsDirectoryPath;
+
+ /**
+ * Count of frequencies read from the {@code time_in_state} file. Read from {@link
+ * #mProcTimeInStateReader#getCpuFrequenciesKhz()}.
+ */
+ private int mFrequencyCount;
+
+ /**
+ * Create with a path where `proc` is mounted. Used primarily for testing
+ *
+ * @param pid PID of the process whose threads are to be read.
+ * @param procPath where `proc` is mounted (to find, see {@code mount | grep ^proc})
+ */
+ @VisibleForTesting
+ public KernelSingleProcessCpuThreadReader(
+ int pid,
+ Path procPath) throws IOException {
+ mPid = pid;
+ mProcPath = procPath;
+ mProcTimeInStateReader = new ProcTimeInStateReader(
+ mProcPath.resolve(INITIAL_TIME_IN_STATE_PATH));
+ long jiffyHz = Os.sysconf(OsConstants._SC_CLK_TCK);
+ mJiffyMillis = 1000 / jiffyHz;
+ mProcessStatFilePath =
+ mProcPath.resolve(String.valueOf(mPid)).resolve(PROC_STAT_FILENAME).toString();
+ mThreadsDirectoryPath =
+ mProcPath.resolve(String.valueOf(mPid)).resolve(THREAD_CPU_STATS_DIRECTORY);
+ }
+
+ /**
+ * Create the reader and handle exceptions during creation
+ *
+ * @return the reader, null if an exception was thrown during creation
+ */
+ @Nullable
+ public static KernelSingleProcessCpuThreadReader create(int pid) {
+ try {
+ return new KernelSingleProcessCpuThreadReader(pid, DEFAULT_PROC_PATH);
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to initialize KernelSingleProcessCpuThreadReader", e);
+ return null;
+ }
+ }
+
+ /**
+ * Get the CPU frequencies that correspond to the times reported in {@link
+ * ThreadCpuUsage#usageTimesMillis}
+ */
+ public int getCpuFrequencyCount() {
+ if (mFrequencyCount == 0) {
+ mFrequencyCount = mProcTimeInStateReader.getFrequenciesKhz().length;
+ }
+ return mFrequencyCount;
+ }
+
+ /**
+ * Get the total and per-thread CPU usage of the process with the PID specified in the
+ * constructor.
+ */
+ @Nullable
+ public ProcessCpuUsage getProcessCpuUsage() {
+ if (DEBUG) {
+ Slog.d(TAG, "Reading CPU thread usages with directory " + mProcPath + " process ID "
+ + mPid);
+ }
+
+ if (!Process.readProcFile(mProcessStatFilePath, PROCESS_FULL_STATS_FORMAT, null,
+ mProcessFullStatsData, null)) {
+ Slog.e(TAG, "Failed to read process stat file " + mProcessStatFilePath);
+ return null;
+ }
+
+ long utime = mProcessFullStatsData[PROCESS_FULL_STAT_UTIME];
+ long stime = mProcessFullStatsData[PROCESS_FULL_STAT_STIME];
+
+ long processCpuTimeMillis = (utime + stime) * mJiffyMillis;
+
+ final ArrayList<ThreadCpuUsage> threadCpuUsages = new ArrayList<>();
+ try (DirectoryStream<Path> threadPaths = Files.newDirectoryStream(mThreadsDirectoryPath)) {
+ for (Path threadDirectory : threadPaths) {
+ ThreadCpuUsage threadCpuUsage = getThreadCpuUsage(threadDirectory);
+ if (threadCpuUsage == null) {
+ continue;
+ }
+ threadCpuUsages.add(threadCpuUsage);
+ }
+ } catch (IOException | DirectoryIteratorException e) {
+ // Expected when a process finishes
+ return null;
+ }
+
+ // If we found no threads, then the process has exited while we were reading from it
+ if (threadCpuUsages.isEmpty()) {
+ return null;
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "Read CPU usage of " + threadCpuUsages.size() + " threads");
+ }
+ return new ProcessCpuUsage(processCpuTimeMillis, threadCpuUsages);
+ }
+
+ /**
+ * Get a thread's CPU usage
+ *
+ * @param threadDirectory the {@code /proc} directory of the thread
+ * @return thread CPU usage. Null if the thread exited and its {@code proc} directory was
+ * removed while collecting information
+ */
+ @Nullable
+ private ThreadCpuUsage getThreadCpuUsage(Path threadDirectory) {
+ // Get the thread ID from the directory name
+ final int threadId;
+ try {
+ final String directoryName = threadDirectory.getFileName().toString();
+ threadId = Integer.parseInt(directoryName);
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "Failed to parse thread ID when iterating over /proc/*/task", e);
+ return null;
+ }
+
+ // Get the CPU statistics from the directory
+ final Path threadCpuStatPath = threadDirectory.resolve(CPU_STATISTICS_FILENAME);
+ final long[] cpuUsages = mProcTimeInStateReader.getUsageTimesMillis(threadCpuStatPath);
+ if (cpuUsages == null) {
+ return null;
+ }
+
+ return new ThreadCpuUsage(threadId, cpuUsages);
+ }
+
+ /** CPU usage of a process and all of its threads */
+ public static class ProcessCpuUsage {
+ public final long cpuTimeMillis;
+ public final List<ThreadCpuUsage> threadCpuUsages;
+
+ ProcessCpuUsage(long cpuTimeMillis, List<ThreadCpuUsage> threadCpuUsages) {
+ this.cpuTimeMillis = cpuTimeMillis;
+ this.threadCpuUsages = threadCpuUsages;
+ }
+ }
+
+ /** CPU usage of a thread */
+ public static class ThreadCpuUsage {
+ public final int threadId;
+ public final long[] usageTimesMillis;
+
+ ThreadCpuUsage(int threadId, long[] usageTimesMillis) {
+ this.threadId = threadId;
+ this.usageTimesMillis = usageTimesMillis;
+ }
+ }
+}
diff --git a/core/java/com/android/internal/os/SystemServerCpuThreadReader.java b/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
index 3aa2390375ec..d9f0dc0ae795 100644
--- a/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
+++ b/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
@@ -16,25 +16,28 @@
package com.android.internal.os;
+import android.annotation.Nullable;
import android.os.Process;
import com.android.internal.annotations.VisibleForTesting;
import java.io.IOException;
import java.nio.file.Path;
-import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
/**
* Reads /proc/UID/task/TID/time_in_state files to obtain statistics on CPU usage
* by various threads of the System Server.
*/
public class SystemServerCpuThreadReader {
- private KernelCpuThreadReader mKernelCpuThreadReader;
+ private final KernelSingleProcessCpuThreadReader mKernelCpuThreadReader;
private int[] mBinderThreadNativeTids = new int[0]; // Sorted
- private int[] mThreadCpuTimesUs;
- private int[] mBinderThreadCpuTimesUs;
+ private long mProcessCpuTimeUs;
+ private long[] mThreadCpuTimesUs;
+ private long[] mBinderThreadCpuTimesUs;
+ private long mLastProcessCpuTimeUs;
private long[] mLastThreadCpuTimesUs;
private long[] mLastBinderThreadCpuTimesUs;
@@ -42,6 +45,8 @@ public class SystemServerCpuThreadReader {
* Times (in microseconds) spent by the system server UID.
*/
public static class SystemServiceCpuThreadTimes {
+ // The entire process
+ public long processCpuTimeUs;
// All threads
public long[] threadCpuTimesUs;
// Just the threads handling incoming binder calls
@@ -55,22 +60,16 @@ public class SystemServerCpuThreadReader {
*/
public static SystemServerCpuThreadReader create() {
return new SystemServerCpuThreadReader(
- KernelCpuThreadReader.create(0, uid -> uid == Process.myUid()));
+ KernelSingleProcessCpuThreadReader.create(Process.myPid()));
}
@VisibleForTesting
- public SystemServerCpuThreadReader(Path procPath, int systemServerUid) throws IOException {
- this(new KernelCpuThreadReader(0, uid -> uid == systemServerUid, null, null,
- new KernelCpuThreadReader.Injector() {
- @Override
- public int getUidForPid(int pid) {
- return systemServerUid;
- }
- }));
+ public SystemServerCpuThreadReader(Path procPath, int pid) throws IOException {
+ this(new KernelSingleProcessCpuThreadReader(pid, procPath));
}
@VisibleForTesting
- public SystemServerCpuThreadReader(KernelCpuThreadReader kernelCpuThreadReader) {
+ public SystemServerCpuThreadReader(KernelSingleProcessCpuThreadReader kernelCpuThreadReader) {
mKernelCpuThreadReader = kernelCpuThreadReader;
}
@@ -82,11 +81,12 @@ public class SystemServerCpuThreadReader {
/**
* Returns delta of CPU times, per thread, since the previous call to this method.
*/
+ @Nullable
public SystemServiceCpuThreadTimes readDelta() {
+ int numCpuFrequencies = mKernelCpuThreadReader.getCpuFrequencyCount();
if (mBinderThreadCpuTimesUs == null) {
- int numCpuFrequencies = mKernelCpuThreadReader.getCpuFrequenciesKhz().length;
- mThreadCpuTimesUs = new int[numCpuFrequencies];
- mBinderThreadCpuTimesUs = new int[numCpuFrequencies];
+ mThreadCpuTimesUs = new long[numCpuFrequencies];
+ mBinderThreadCpuTimesUs = new long[numCpuFrequencies];
mLastThreadCpuTimesUs = new long[numCpuFrequencies];
mLastBinderThreadCpuTimesUs = new long[numCpuFrequencies];
@@ -95,49 +95,47 @@ public class SystemServerCpuThreadReader {
mDeltaCpuThreadTimes.binderThreadCpuTimesUs = new long[numCpuFrequencies];
}
+ mProcessCpuTimeUs = 0;
Arrays.fill(mThreadCpuTimesUs, 0);
Arrays.fill(mBinderThreadCpuTimesUs, 0);
- ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsage =
+ KernelSingleProcessCpuThreadReader.ProcessCpuUsage processCpuUsage =
mKernelCpuThreadReader.getProcessCpuUsage();
- int processCpuUsageSize = processCpuUsage.size();
- for (int i = 0; i < processCpuUsageSize; i++) {
- KernelCpuThreadReader.ProcessCpuUsage pcu = processCpuUsage.get(i);
- ArrayList<KernelCpuThreadReader.ThreadCpuUsage> threadCpuUsages = pcu.threadCpuUsages;
- if (threadCpuUsages != null) {
- int threadCpuUsagesSize = threadCpuUsages.size();
- for (int j = 0; j < threadCpuUsagesSize; j++) {
- KernelCpuThreadReader.ThreadCpuUsage tcu = threadCpuUsages.get(j);
- boolean isBinderThread =
- Arrays.binarySearch(mBinderThreadNativeTids, tcu.threadId) >= 0;
-
- final int len = Math.min(tcu.usageTimesMillis.length, mThreadCpuTimesUs.length);
- for (int k = 0; k < len; k++) {
- int usageTimeUs = tcu.usageTimesMillis[k] * 1000;
- mThreadCpuTimesUs[k] += usageTimeUs;
- if (isBinderThread) {
- mBinderThreadCpuTimesUs[k] += usageTimeUs;
- }
- }
+ if (processCpuUsage == null) {
+ return null;
+ }
+
+ mProcessCpuTimeUs = processCpuUsage.cpuTimeMillis * 1000;
+
+ List<KernelSingleProcessCpuThreadReader.ThreadCpuUsage> threadCpuUsages =
+ processCpuUsage.threadCpuUsages;
+ int threadCpuUsagesSize = threadCpuUsages.size();
+ for (int i = 0; i < threadCpuUsagesSize; i++) {
+ KernelSingleProcessCpuThreadReader.ThreadCpuUsage tcu = threadCpuUsages.get(i);
+ boolean isBinderThread =
+ Arrays.binarySearch(mBinderThreadNativeTids, tcu.threadId) >= 0;
+ for (int k = 0; k < numCpuFrequencies; k++) {
+ long usageTimeUs = tcu.usageTimesMillis[k] * 1000;
+ mThreadCpuTimesUs[k] += usageTimeUs;
+ if (isBinderThread) {
+ mBinderThreadCpuTimesUs[k] += usageTimeUs;
}
}
}
for (int i = 0; i < mThreadCpuTimesUs.length; i++) {
- if (mThreadCpuTimesUs[i] < mLastThreadCpuTimesUs[i]) {
- mDeltaCpuThreadTimes.threadCpuTimesUs[i] = mThreadCpuTimesUs[i];
- mDeltaCpuThreadTimes.binderThreadCpuTimesUs[i] = mBinderThreadCpuTimesUs[i];
- } else {
- mDeltaCpuThreadTimes.threadCpuTimesUs[i] =
- mThreadCpuTimesUs[i] - mLastThreadCpuTimesUs[i];
- mDeltaCpuThreadTimes.binderThreadCpuTimesUs[i] =
- mBinderThreadCpuTimesUs[i] - mLastBinderThreadCpuTimesUs[i];
- }
+ mDeltaCpuThreadTimes.processCpuTimeUs =
+ Math.max(0, mProcessCpuTimeUs - mLastProcessCpuTimeUs);
+ mDeltaCpuThreadTimes.threadCpuTimesUs[i] =
+ Math.max(0, mThreadCpuTimesUs[i] - mLastThreadCpuTimesUs[i]);
+ mDeltaCpuThreadTimes.binderThreadCpuTimesUs[i] =
+ Math.max(0, mBinderThreadCpuTimesUs[i] - mLastBinderThreadCpuTimesUs[i]);
mLastThreadCpuTimesUs[i] = mThreadCpuTimesUs[i];
mLastBinderThreadCpuTimesUs[i] = mBinderThreadCpuTimesUs[i];
}
+ mLastProcessCpuTimeUs = mProcessCpuTimeUs;
+
return mDeltaCpuThreadTimes;
}
-
}
diff --git a/core/java/com/android/internal/os/SystemServicePowerCalculator.java b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
index 481b901b3c69..fc36e50950e9 100644
--- a/core/java/com/android/internal/os/SystemServicePowerCalculator.java
+++ b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
@@ -34,7 +34,9 @@ public class SystemServicePowerCalculator extends PowerCalculator {
private final PowerProfile mPowerProfile;
private final BatteryStats mBatteryStats;
// Tracks system server CPU [cluster][speed] power in milliAmp-microseconds
- private double[][] mSystemServicePowerMaUs;
+ // Data organized like this:
+ // {cluster1-speed1, cluster1-speed2, ..., cluster2-speed1, cluster2-speed2, ...}
+ private double[] mSystemServicePowerMaUs;
public SystemServicePowerCalculator(PowerProfile powerProfile, BatteryStats batteryStats) {
mPowerProfile = powerProfile;
@@ -50,37 +52,41 @@ public class SystemServicePowerCalculator extends PowerCalculator {
updateSystemServicePower();
}
- double cpuPowerMaUs = 0;
- int numCpuClusters = mPowerProfile.getNumCpuClusters();
- for (int cluster = 0; cluster < numCpuClusters; cluster++) {
- final int numSpeeds = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
- for (int speed = 0; speed < numSpeeds; speed++) {
- cpuPowerMaUs += mSystemServicePowerMaUs[cluster][speed] * proportionalUsage;
+ if (mSystemServicePowerMaUs != null) {
+ double cpuPowerMaUs = 0;
+ for (int i = 0; i < mSystemServicePowerMaUs.length; i++) {
+ cpuPowerMaUs += mSystemServicePowerMaUs[i] * proportionalUsage;
}
- }
- app.systemServiceCpuPowerMah = cpuPowerMaUs / MICROSEC_IN_HR;
+ app.systemServiceCpuPowerMah = cpuPowerMaUs / MICROSEC_IN_HR;
+ }
}
}
private void updateSystemServicePower() {
+ final long[] systemServiceTimeAtCpuSpeeds = mBatteryStats.getSystemServiceTimeAtCpuSpeeds();
+ if (systemServiceTimeAtCpuSpeeds == null) {
+ return;
+ }
+
+ if (mSystemServicePowerMaUs == null) {
+ mSystemServicePowerMaUs = new double[systemServiceTimeAtCpuSpeeds.length];
+ }
+ int index = 0;
final int numCpuClusters = mPowerProfile.getNumCpuClusters();
- mSystemServicePowerMaUs = new double[numCpuClusters][];
for (int cluster = 0; cluster < numCpuClusters; cluster++) {
final int numSpeeds = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
- mSystemServicePowerMaUs[cluster] = new double[numSpeeds];
for (int speed = 0; speed < numSpeeds; speed++) {
- mSystemServicePowerMaUs[cluster][speed] =
- mBatteryStats.getSystemServiceTimeAtCpuSpeed(cluster, speed)
+ mSystemServicePowerMaUs[index] =
+ systemServiceTimeAtCpuSpeeds[index]
* mPowerProfile.getAveragePowerForCpuCore(cluster, speed);
+ index++;
}
}
+
if (DEBUG) {
- Log.d(TAG, "System service power per CPU cluster and frequency");
- for (int cluster = 0; cluster < numCpuClusters; cluster++) {
- Log.d(TAG, "Cluster[" + cluster + "]: "
- + Arrays.toString(mSystemServicePowerMaUs[cluster]));
- }
+ Log.d(TAG, "System service power per CPU cluster and frequency:"
+ + Arrays.toString(mSystemServicePowerMaUs));
}
}
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index d5f54a199828..fff9ac9e49b7 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -43,7 +43,6 @@ public class BaseIWindow extends IWindow.Stub {
public BaseIWindow() {}
private IWindowSession mSession;
- public int mSeq;
public void setSession(IWindowSession session) {
mSession = session;
@@ -140,12 +139,6 @@ public class BaseIWindow extends IWindow.Stub {
}
@Override
- public void dispatchSystemUiVisibilityChanged(int seq, int globalUi,
- int localValue, int localChanges) {
- mSeq = seq;
- }
-
- @Override
public void dispatchWallpaperCommand(String action, int x, int y,
int z, Bundle extras, boolean sync) {
if (sync) {
diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl
index 45090320c192..c9443b002133 100644
--- a/core/java/com/android/internal/view/IInputMethodClient.aidl
+++ b/core/java/com/android/internal/view/IInputMethodClient.aidl
@@ -33,4 +33,5 @@ oneway interface IInputMethodClient {
void reportPreRendered(in EditorInfo info);
void applyImeVisibility(boolean setVisible);
void updateActivityViewToScreenMatrix(int bindSequence, in float[] matrixValues);
+ void setImeTraceEnabled(boolean enabled);
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index a1cbd3fcae79..5a06273bb173 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -77,4 +77,6 @@ interface IInputMethodManager {
void removeImeSurface();
/** Remove the IME surface. Requires passing the currently focused window. */
void removeImeSurfaceFromWindow(in IBinder windowToken);
+ void startProtoDump(in byte[] clientProtoDump);
+ boolean isImeTraceEnabled();
}
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index ddee81a649af..ff3543c837eb 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -17,9 +17,6 @@
package com.android.internal.widget;
import android.compat.annotation.UnsupportedAppUsage;
-import android.content.ClipData;
-import android.content.ClipDescription;
-import android.os.Build;
import android.os.Bundle;
import android.text.Editable;
import android.text.method.KeyListener;
@@ -30,8 +27,6 @@ import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputContentInfo;
-import android.widget.RichContentReceiver;
import android.widget.TextView;
public class EditableInputConnection extends BaseInputConnection {
@@ -186,28 +181,6 @@ public class EditableInputConnection extends BaseInputConnection {
}
@Override
- public boolean commitContent(InputContentInfo content, int flags, Bundle opts) {
- int targetSdkVersion = mTextView.getContext().getApplicationInfo().targetSdkVersion;
- if (targetSdkVersion <= Build.VERSION_CODES.R) {
- return false;
- }
-
- final ClipDescription description = content.getDescription();
- final RichContentReceiver<TextView> receiver = mTextView.getRichContentReceiver();
- if ((flags & InputConnection.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
- try {
- content.requestPermission();
- } catch (Exception e) {
- // TODO(b/147299828): Can we catch SecurityException instead?
- Log.w(TAG, "Can't insert content from IME; requestPermission() failed: " + e);
- return false; // Can't insert the content if we don't have permission to read it
- }
- }
- ClipData clip = new ClipData(description, new ClipData.Item(content.getContentUri()));
- return receiver.onReceive(mTextView, clip, RichContentReceiver.SOURCE_INPUT_METHOD, 0);
- }
-
- @Override
public boolean requestCursorUpdates(int cursorUpdateMode) {
if (DEBUG) Log.v(TAG, "requestUpdateCursorAnchorInfo " + cursorUpdateMode);
diff --git a/core/jni/core_jni_helpers.h b/core/jni/core_jni_helpers.h
index d629e0dae6dd..013c65faa241 100644
--- a/core/jni/core_jni_helpers.h
+++ b/core/jni/core_jni_helpers.h
@@ -90,6 +90,12 @@ static inline int RegisterMethodsOrDie(JNIEnv* env, const char* className,
return res;
}
+static inline jobject jniGetReferent(JNIEnv* env, jobject ref) {
+ jclass cls = FindClassOrDie(env, "java/lang/ref/Reference");
+ jmethodID get = GetMethodIDOrDie(env, cls, "get", "()Ljava/lang/Object;");
+ return env->CallObjectMethod(ref, get);
+}
+
/**
* Read the specified field from jobject, and convert to std::string.
* If the field cannot be obtained, return defaultValue.
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index 11f6a912faf7..542d26fa233e 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -17,6 +17,9 @@ jjaggi@google.com
roosa@google.com
per-file usagestatsservice.proto, usagestatsservice_v2.proto = mwachens@google.com
+# Biometrics
+kchyn@google.com
+
# Launcher
hyunyoungs@google.com
diff --git a/core/proto/android/server/peopleservice.proto b/core/proto/android/server/peopleservice.proto
index 59556c4414ce..c465233036c4 100644
--- a/core/proto/android/server/peopleservice.proto
+++ b/core/proto/android/server/peopleservice.proto
@@ -46,6 +46,10 @@ message ConversationInfoProto {
// The notification channel id of the conversation.
optional string notification_channel_id = 4 [(.android.privacy).dest = DEST_EXPLICIT];
+ // The parent notification channel ID of the conversation. This is the notification channel where
+ // the notifications are posted before this conversation is customized by the user.
+ optional string parent_notification_channel_id = 8 [(.android.privacy).dest = DEST_EXPLICIT];
+
// Integer representation of shortcut bit flags.
optional int32 shortcut_flags = 5;
@@ -54,6 +58,11 @@ message ConversationInfoProto {
// The phone number of the contact.
optional string contact_phone_number = 7 [(.android.privacy).dest = DEST_EXPLICIT];
+
+ // The timestamp of the last event in millis.
+ optional int64 last_event_timestamp = 9;
+
+ // Next tag: 10
}
// On disk data of events.
diff --git a/core/proto/android/telephony/enums.proto b/core/proto/android/telephony/enums.proto
index f14e3ed1872d..b56bd2bae29a 100644
--- a/core/proto/android/telephony/enums.proto
+++ b/core/proto/android/telephony/enums.proto
@@ -159,3 +159,50 @@ enum SimStateEnum {
*/
SIM_STATE_PRESENT = 11;
}
+
+// Format of SMS message
+enum SmsFormatEnum {
+ /** Unknown format */
+ SMS_FORMAT_UNKNOWN = 0;
+ /** Format compliant with 3GPP TS 23.040 */
+ SMS_FORMAT_3GPP = 1;
+ /** Format compliant with 3GPP2 TS C.S0015-B */
+ SMS_FORMAT_3GPP2 = 2;
+}
+
+// Technology used to carry an SMS message
+enum SmsTechEnum {
+ /**
+ * Unknown SMS technology used to carry the SMS.
+ * This value is also used for injected SMS.
+ */
+ SMS_TECH_UNKNOWN = 0;
+ /** The SMS was carried over CS bearer in 3GPP network */
+ SMS_TECH_CS_3GPP = 1;
+ /** The SMS was carried over CS bearer in 3GPP2 network */
+ SMS_TECH_CS_3GPP2 = 2;
+ /** The SMS was carried over IMS */
+ SMS_TECH_IMS = 3;
+}
+
+// Types of SMS message
+enum SmsTypeEnum {
+ /** Normal type. */
+ SMS_TYPE_NORMAL = 0;
+ /** SMS-PP (point-to-point). */
+ SMS_TYPE_SMS_PP = 1;
+ /** Voicemail indication. */
+ SMS_TYPE_VOICEMAIL_INDICATION = 2;
+ /** Type 0 message (3GPP TS 23.040 9.2.3.9). */
+ SMS_TYPE_ZERO = 3;
+ /** WAP-PUSH message. */
+ SMS_TYPE_WAP_PUSH = 4;
+}
+
+// SMS errors
+enum SmsIncomingErrorEnum {
+ SMS_SUCCESS = 0;
+ SMS_ERROR_GENERIC = 1;
+ SMS_ERROR_NO_MEMORY = 2;
+ SMS_ERROR_NOT_SUPPORTED = 3;
+}
diff --git a/core/proto/android/view/imeinsetssourceconsumer.proto b/core/proto/android/view/imeinsetssourceconsumer.proto
index 680916345a31..5bee81bdc7cd 100644
--- a/core/proto/android/view/imeinsetssourceconsumer.proto
+++ b/core/proto/android/view/imeinsetssourceconsumer.proto
@@ -17,6 +17,7 @@
syntax = "proto2";
import "frameworks/base/core/proto/android/view/inputmethod/editorinfo.proto";
+import "frameworks/base/core/proto/android/view/insetssourceconsumer.proto";
package android.view;
@@ -26,6 +27,7 @@ option java_multiple_files = true;
* Represents a {@link android.view.ImeInsetsSourceConsumer} object.
*/
message ImeInsetsSourceConsumerProto {
- optional .android.view.inputmethod.EditorInfoProto focused_editor = 1;
- optional bool is_requested_visible_awaiting_control = 2;
+ optional InsetsSourceConsumerProto insets_source_consumer = 1;
+ optional .android.view.inputmethod.EditorInfoProto focused_editor = 2;
+ optional bool is_requested_visible_awaiting_control = 3;
} \ No newline at end of file
diff --git a/core/proto/android/view/inputmethod/inputmethodeditortrace.proto b/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
index 732213966014..f31d35b86a0c 100644
--- a/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
+++ b/core/proto/android/view/inputmethod/inputmethodeditortrace.proto
@@ -22,7 +22,6 @@ package android.view.inputmethod;
import "frameworks/base/core/proto/android/view/inputmethod/inputmethodmanager.proto";
import "frameworks/base/core/proto/android/view/viewrootimpl.proto";
import "frameworks/base/core/proto/android/view/insetscontroller.proto";
-import "frameworks/base/core/proto/android/view/insetssourceconsumer.proto";
import "frameworks/base/core/proto/android/view/imeinsetssourceconsumer.proto";
import "frameworks/base/core/proto/android/view/inputmethod/editorinfo.proto";
import "frameworks/base/core/proto/android/view/imefocuscontroller.proto";
@@ -54,14 +53,19 @@ message InputMethodEditorProto {
/* required: elapsed realtime in nanos since boot of when this entry was logged */
optional fixed64 elapsed_realtime_nanos = 1;
- optional ClientSideProto client_side_dump = 2;
+ optional ClientsProto clients = 2;
+
+ // this wrapper helps to simplify the dumping logic
+ message ClientsProto {
+ repeated ClientSideProto client = 1;
+ }
/* groups together the dump from ime related client side classes */
message ClientSideProto {
- optional InputMethodManagerProto input_method_manager = 1;
- optional ViewRootImplProto view_root_impl = 2;
- optional InsetsControllerProto insets_controller = 3;
- optional InsetsSourceConsumerProto insets_source_consumer = 4;
+ optional int32 display_id = 1;
+ optional InputMethodManagerProto input_method_manager = 2;
+ optional ViewRootImplProto view_root_impl = 3;
+ optional InsetsControllerProto insets_controller = 4;
optional ImeInsetsSourceConsumerProto ime_insets_source_consumer = 5;
optional EditorInfoProto editor_info = 6;
optional ImeFocusControllerProto ime_focus_controller = 7;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 34543f13c166..723cceba90bc 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4322,6 +4322,10 @@
<permission android:name="android.permission.WRITE_DREAM_STATE"
android:protectionLevel="signature|privileged" />
+ <!-- @hide Allows applications to read whether ambient display is suppressed. -->
+ <permission android:name="android.permission.READ_DREAM_SUPPRESSION"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allow an application to read and write the cache partition.
@hide -->
<permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM"
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 71cb2acde94e..56f18d5dc1d7 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1599,6 +1599,7 @@
</activity>
<activity android:name="android.app.activity.ActivityThreadTest$TestActivity"
+ android:configChanges="screenLayout|screenSize|orientation|smallestScreenSize"
android:supportsPictureInPicture="true"
android:exported="true">
</activity>
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 23534e2ebebc..8b25afba228e 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -69,6 +69,7 @@ import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Test for verifying {@link android.app.ActivityThread} class.
@@ -78,6 +79,7 @@ import java.util.concurrent.CountDownLatch;
@RunWith(AndroidJUnit4.class)
@MediumTest
public class ActivityThreadTest {
+ private static final int TIMEOUT_SEC = 10;
// The first sequence number to try with. Use a large number to avoid conflicts with the first a
// few sequence numbers the framework used to launch the test activity.
@@ -309,7 +311,7 @@ public class ActivityThreadTest {
transaction.addCallback(ActivityConfigurationChangeItem.obtain(activityConfigPortrait));
appThread.scheduleTransaction(transaction);
- activity.mTestLatch.await();
+ activity.mTestLatch.await(TIMEOUT_SEC, TimeUnit.SECONDS);
activity.mConfigLatch.countDown();
activity.mConfigLatch = null;
@@ -352,7 +354,7 @@ public class ActivityThreadTest {
// Wait until the main thread is performing the configuration change for the configuration
// with sequence number BASE_SEQ + 1 before proceeding. This is to mimic the situation where
// the activity takes very long time to process configuration changes.
- activity.mTestLatch.await();
+ activity.mTestLatch.await(TIMEOUT_SEC, TimeUnit.SECONDS);
config = new Configuration();
config.seq = BASE_SEQ + 2;
@@ -738,7 +740,7 @@ public class ActivityThreadTest {
mTestLatch.countDown();
}
try {
- mConfigLatch.await();
+ mConfigLatch.await(TIMEOUT_SEC, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
diff --git a/core/tests/coretests/src/android/view/InsetsFlagsTest.java b/core/tests/coretests/src/android/view/InsetsFlagsTest.java
deleted file mode 100644
index b4302e79ed6a..000000000000
--- a/core/tests/coretests/src/android/view/InsetsFlagsTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view;
-
-
-import static android.view.InsetsFlags.getAppearance;
-import static android.view.View.NAVIGATION_BAR_TRANSLUCENT;
-import static android.view.View.NAVIGATION_BAR_TRANSPARENT;
-import static android.view.View.STATUS_BAR_TRANSLUCENT;
-import static android.view.View.STATUS_BAR_TRANSPARENT;
-import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
-import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
-import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
-import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
-import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
-import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
-import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
-import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS;
-
-import static org.junit.Assert.assertTrue;
-
-import android.platform.test.annotations.Presubmit;
-import android.view.WindowInsetsController.Appearance;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for {@link InsetsFlags}.
- *
- * <p>Build/Install/Run:
- * atest FrameworksCoreTests:InsetsFlagsTest
- *
- * <p>This test class is a part of Window Manager Service tests and specified in
- * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
- */
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-public class InsetsFlagsTest {
-
- @Test
- public void testGetAppearance() {
- assertContainsAppearance(APPEARANCE_LOW_PROFILE_BARS, SYSTEM_UI_FLAG_LOW_PROFILE);
- assertContainsAppearance(APPEARANCE_LIGHT_STATUS_BARS, SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
- assertContainsAppearance(APPEARANCE_LIGHT_NAVIGATION_BARS,
- SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
- assertContainsAppearance(APPEARANCE_OPAQUE_STATUS_BARS,
- 0xffffffff & ~(STATUS_BAR_TRANSLUCENT | STATUS_BAR_TRANSPARENT));
- assertContainsAppearance(APPEARANCE_OPAQUE_NAVIGATION_BARS,
- 0xffffffff & ~(NAVIGATION_BAR_TRANSLUCENT | NAVIGATION_BAR_TRANSPARENT));
- }
-
- void assertContainsAppearance(@Appearance int appearance, int systemUiVisibility) {
- assertTrue((getAppearance(systemUiVisibility) & appearance) == appearance);
- }
-}
diff --git a/core/tests/coretests/src/android/widget/TextViewProcessTextTest.java b/core/tests/coretests/src/android/widget/TextViewProcessTextTest.java
index ec8dfcbfbde9..91266f0bbb9e 100644
--- a/core/tests/coretests/src/android/widget/TextViewProcessTextTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewProcessTextTest.java
@@ -16,20 +16,10 @@
package android.widget;
-import static android.widget.RichContentReceiver.SOURCE_PROCESS_TEXT;
-
import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
import android.app.Activity;
import android.app.Instrumentation;
-import android.content.ClipData;
-import android.content.ClipDescription;
import android.content.Intent;
import android.text.Selection;
import android.text.Spannable;
@@ -44,10 +34,6 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatcher;
-import org.mockito.Mockito;
-
-import java.util.Set;
/**
* Tests for {@link Intent#ACTION_PROCESS_TEXT} functionality in {@link TextView}.
@@ -78,9 +64,6 @@ public class TextViewProcessTextTest {
mTextView.setTextIsSelectable(true);
Selection.setSelection((Spannable) mTextView.getText(), 0, mTextView.getText().length());
- MockReceiverWrapper mockReceiverWrapper = new MockReceiverWrapper();
- mTextView.setRichContentReceiver(mockReceiverWrapper);
-
// We need to run this in the UI thread, as it will create a Toast.
mActivityRule.runOnUiThread(() -> {
triggerOnActivityResult(Activity.RESULT_OK, "Text is replaced.");
@@ -89,46 +72,6 @@ public class TextViewProcessTextTest {
// This is a TextView, which can't be modified. Hence no change should have been made.
assertEquals(originalText, mTextView.getText().toString());
- verifyZeroInteractions(mockReceiverWrapper.mMock);
- }
-
- @Test
- public void testProcessTextActivityResultEditable_defaultRichContentReceiver()
- throws Throwable {
- mActivityRule.runOnUiThread(() -> mTextView = new EditText(mActivity));
- mInstrumentation.waitForIdleSync();
- CharSequence originalText = "This is some text.";
- mTextView.setText(originalText, BufferType.SPANNABLE);
- assertEquals(originalText, mTextView.getText().toString());
- mTextView.setTextIsSelectable(true);
- Selection.setSelection(((EditText) mTextView).getText(), 0, mTextView.getText().length());
-
- CharSequence newText = "Text is replaced.";
- triggerOnActivityResult(Activity.RESULT_OK, newText);
-
- assertEquals(newText, mTextView.getText().toString());
- }
-
- @Test
- public void testProcessTextActivityResultEditable_customRichContentReceiver() throws Throwable {
- mActivityRule.runOnUiThread(() -> mTextView = new EditText(mActivity));
- mInstrumentation.waitForIdleSync();
- CharSequence originalText = "This is some text.";
- mTextView.setText(originalText, BufferType.SPANNABLE);
- assertEquals(originalText, mTextView.getText().toString());
- mTextView.setTextIsSelectable(true);
- Selection.setSelection(((EditText) mTextView).getText(), 0, mTextView.getText().length());
-
- MockReceiverWrapper mockReceiverWrapper = new MockReceiverWrapper();
- mTextView.setRichContentReceiver(mockReceiverWrapper);
-
- CharSequence newText = "Text is replaced.";
- triggerOnActivityResult(Activity.RESULT_OK, newText);
-
- ClipData expectedClip = ClipData.newPlainText("", newText);
- verify(mockReceiverWrapper.mMock, times(1)).onReceive(
- eq(mTextView), clipEq(expectedClip), eq(SOURCE_PROCESS_TEXT), eq(0));
- verifyNoMoreInteractions(mockReceiverWrapper.mMock);
}
@Test
@@ -141,14 +84,10 @@ public class TextViewProcessTextTest {
mTextView.setTextIsSelectable(true);
Selection.setSelection(((EditText) mTextView).getText(), 0, mTextView.getText().length());
- MockReceiverWrapper mockReceiverWrapper = new MockReceiverWrapper();
- mTextView.setRichContentReceiver(mockReceiverWrapper);
-
CharSequence newText = "Text is replaced.";
triggerOnActivityResult(Activity.RESULT_CANCELED, newText);
assertEquals(originalText, mTextView.getText().toString());
- verifyZeroInteractions(mockReceiverWrapper.mMock);
}
@Test
@@ -161,13 +100,9 @@ public class TextViewProcessTextTest {
mTextView.setTextIsSelectable(true);
Selection.setSelection(((EditText) mTextView).getText(), 0, mTextView.getText().length());
- MockReceiverWrapper mockReceiverWrapper = new MockReceiverWrapper();
- mTextView.setRichContentReceiver(mockReceiverWrapper);
-
mTextView.onActivityResult(TextView.PROCESS_TEXT_REQUEST_CODE, Activity.RESULT_OK, null);
assertEquals(originalText, mTextView.getText().toString());
- verifyZeroInteractions(mockReceiverWrapper.mMock);
}
private void triggerOnActivityResult(int resultCode, CharSequence replacementText) {
@@ -175,55 +110,4 @@ public class TextViewProcessTextTest {
data.putExtra(Intent.EXTRA_PROCESS_TEXT, replacementText);
mTextView.onActivityResult(TextView.PROCESS_TEXT_REQUEST_CODE, resultCode, data);
}
-
- // This wrapper is used so that we only mock and verify the public callback methods. In addition
- // to the public methods, the RichContentReceiver interface has some hidden default methods;
- // we don't want to mock or assert calls to these helper functions (they are an implementation
- // detail).
- private static class MockReceiverWrapper implements RichContentReceiver<TextView> {
- private final RichContentReceiver<TextView> mMock;
-
- @SuppressWarnings("unchecked")
- MockReceiverWrapper() {
- this.mMock = Mockito.mock(RichContentReceiver.class);
- }
-
- public RichContentReceiver<TextView> getMock() {
- return mMock;
- }
-
- @Override
- public boolean onReceive(TextView view, ClipData clip, @Source int source,
- @Flags int flags) {
- return mMock.onReceive(view, clip, source, flags);
- }
-
- @Override
- public Set<String> getSupportedMimeTypes() {
- return mMock.getSupportedMimeTypes();
- }
- }
-
- private static ClipData clipEq(ClipData expected) {
- return argThat(new ClipDataArgumentMatcher(expected));
- }
-
- private static class ClipDataArgumentMatcher implements ArgumentMatcher<ClipData> {
- private final ClipData mExpected;
-
- private ClipDataArgumentMatcher(ClipData expected) {
- this.mExpected = expected;
- }
-
- @Override
- public boolean matches(ClipData actual) {
- ClipDescription actualDesc = actual.getDescription();
- ClipDescription expectedDesc = mExpected.getDescription();
- return expectedDesc.getLabel().equals(actualDesc.getLabel())
- && actualDesc.getMimeTypeCount() == 1
- && expectedDesc.getMimeType(0).equals(actualDesc.getMimeType(0))
- && actual.getItemCount() == 1
- && mExpected.getItemAt(0).getText().equals(actual.getItemAt(0).getText());
- }
- }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java
new file mode 100644
index 000000000000..403c1c219a52
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.os.FileUtils;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Comparator;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KernelSingleProcessCpuThreadReaderTest {
+
+ private File mProcDirectory;
+
+ @Before
+ public void setUp() {
+ Context context = InstrumentationRegistry.getContext();
+ mProcDirectory = context.getDir("proc", Context.MODE_PRIVATE);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ FileUtils.deleteContents(mProcDirectory);
+ }
+
+ @Test
+ public void getThreadCpuUsage() throws IOException {
+ setupDirectory(42,
+ new int[] {42, 1, 2, 3},
+ new int[] {1000, 2000},
+ // Units are 10ms aka 10000Us
+ new int[][] {{100, 200}, {0, 200}, {100, 300}, {0, 400}},
+ new int[] {1400, 1500});
+
+ KernelSingleProcessCpuThreadReader reader = new KernelSingleProcessCpuThreadReader(42,
+ mProcDirectory.toPath());
+ KernelSingleProcessCpuThreadReader.ProcessCpuUsage processCpuUsage =
+ reader.getProcessCpuUsage();
+ assertThat(processCpuUsage.cpuTimeMillis).isEqualTo(29000);
+ List<KernelSingleProcessCpuThreadReader.ThreadCpuUsage> threadCpuUsage =
+ processCpuUsage.threadCpuUsages;
+ threadCpuUsage.sort(Comparator.comparingInt(o -> o.threadId));
+ assertThat(threadCpuUsage).hasSize(4);
+ assertThat(threadCpuUsage.get(0).threadId).isEqualTo(1);
+ assertThat(threadCpuUsage.get(0).usageTimesMillis).isEqualTo(new long[]{0, 2000});
+ assertThat(threadCpuUsage.get(1).threadId).isEqualTo(2);
+ assertThat(threadCpuUsage.get(1).usageTimesMillis).isEqualTo(new long[]{1000, 3000});
+ assertThat(threadCpuUsage.get(2).threadId).isEqualTo(3);
+ assertThat(threadCpuUsage.get(2).usageTimesMillis).isEqualTo(new long[]{0, 4000});
+ assertThat(threadCpuUsage.get(3).threadId).isEqualTo(42);
+ assertThat(threadCpuUsage.get(3).usageTimesMillis).isEqualTo(new long[]{1000, 2000});
+ }
+
+ @Test
+ public void getCpuFrequencyCount() throws IOException {
+ setupDirectory(13,
+ new int[] {13},
+ new int[] {1000, 2000, 3000},
+ new int[][] {{100, 200, 300}},
+ new int[] {14, 15});
+
+ KernelSingleProcessCpuThreadReader reader = new KernelSingleProcessCpuThreadReader(13,
+ mProcDirectory.toPath());
+ int cpuFrequencyCount = reader.getCpuFrequencyCount();
+ assertThat(cpuFrequencyCount).isEqualTo(3);
+ }
+
+ private void setupDirectory(int pid, int[] threadIds, int[] cpuFrequencies,
+ int[][] threadCpuTimes, int[] processCpuTimes)
+ throws IOException {
+
+ assertTrue(mProcDirectory.toPath().resolve("self").toFile().mkdirs());
+
+ try (OutputStream timeInStateStream =
+ Files.newOutputStream(
+ mProcDirectory.toPath().resolve("self").resolve("time_in_state"))) {
+ for (int i = 0; i < cpuFrequencies.length; i++) {
+ final String line = cpuFrequencies[i] + " 0\n";
+ timeInStateStream.write(line.getBytes());
+ }
+ }
+
+ Path processPath = mProcDirectory.toPath().resolve(String.valueOf(pid));
+
+ // Make /proc/$PID
+ assertTrue(processPath.toFile().mkdirs());
+
+ // Write /proc/$PID/stat. Only the fields 14-17 matter.
+ try (OutputStream timeInStateStream = Files.newOutputStream(processPath.resolve("stat"))) {
+ timeInStateStream.write(
+ (pid + " (test) S 4 5 6 7 8 9 10 11 12 13 "
+ + processCpuTimes[0] + " "
+ + processCpuTimes[1] + " "
+ + "16 17 18 19 20 ...").getBytes());
+ }
+
+ // Make /proc/$PID/task
+ final Path selfThreadsPath = processPath.resolve("task");
+ assertTrue(selfThreadsPath.toFile().mkdirs());
+
+ // Make thread directories
+ for (int i = 0; i < threadIds.length; i++) {
+ // Make /proc/$PID/task/$TID
+ final Path threadPath = selfThreadsPath.resolve(String.valueOf(threadIds[i]));
+ assertTrue(threadPath.toFile().mkdirs());
+
+ // Make /proc/$PID/task/$TID/time_in_state
+ try (OutputStream timeInStateStream =
+ Files.newOutputStream(threadPath.resolve("time_in_state"))) {
+ for (int j = 0; j < cpuFrequencies.length; j++) {
+ final String line = cpuFrequencies[j] + " " + threadCpuTimes[i][j] + "\n";
+ timeInStateStream.write(line.getBytes());
+ }
+ }
+ }
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
index 10ba54865dbe..121c637310c6 100644
--- a/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
@@ -55,82 +55,107 @@ public class SystemServerCpuThreadReaderTest {
@Test
public void testReaderDelta_firstTime() throws IOException {
- int uid = 42;
+ int pid = 42;
setupDirectory(
- mProcDirectory.toPath().resolve(String.valueOf(uid)),
- new int[]{42, 1, 2, 3},
- new int[]{1000, 2000},
+ pid,
+ new int[] {42, 1, 2, 3},
+ new int[] {1000, 2000},
// Units are 10ms aka 10000Us
- new int[][]{{100, 200}, {0, 200}, {0, 300}, {0, 400}});
+ new int[][] {{100, 200}, {0, 200}, {0, 300}, {0, 400}},
+ new int[] {1400, 1500});
SystemServerCpuThreadReader reader = new SystemServerCpuThreadReader(
- mProcDirectory.toPath(), uid);
- reader.setBinderThreadNativeTids(new int[]{1, 3});
+ mProcDirectory.toPath(), pid);
+ reader.setBinderThreadNativeTids(new int[] {1, 3});
SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
reader.readDelta();
- assertArrayEquals(new long[]{100 * 10000, 1100 * 10000},
+ assertArrayEquals(new long[] {100 * 10000, 1100 * 10000},
systemServiceCpuThreadTimes.threadCpuTimesUs);
- assertArrayEquals(new long[]{0, 600 * 10000},
+ assertArrayEquals(new long[] {0, 600 * 10000},
systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
}
@Test
public void testReaderDelta_nextTime() throws IOException {
- int uid = 42;
+ int pid = 42;
setupDirectory(
- mProcDirectory.toPath().resolve(String.valueOf(uid)),
- new int[]{42, 1, 2, 3},
- new int[]{1000, 2000},
- new int[][]{{100, 200}, {0, 200}, {0, 300}, {0, 400}});
+ pid,
+ new int[] {42, 1, 2, 3},
+ new int[] {1000, 2000},
+ new int[][] {{100, 200}, {0, 200}, {0, 300}, {0, 400}},
+ new int[] {1400, 1500});
SystemServerCpuThreadReader reader = new SystemServerCpuThreadReader(
- mProcDirectory.toPath(), uid);
- reader.setBinderThreadNativeTids(new int[]{1, 3});
+ mProcDirectory.toPath(), pid);
+ reader.setBinderThreadNativeTids(new int[] {1, 3});
// First time, populate "last" snapshot
reader.readDelta();
FileUtils.deleteContents(mProcDirectory);
setupDirectory(
- mProcDirectory.toPath().resolve(String.valueOf(uid)),
- new int[]{42, 1, 2, 3},
- new int[]{1000, 2000},
- new int[][]{{500, 600}, {700, 800}, {900, 1000}, {1100, 1200}});
+ pid,
+ new int[] {42, 1, 2, 3},
+ new int[] {1000, 2000},
+ new int[][] {{500, 600}, {700, 800}, {900, 1000}, {1100, 1200}},
+ new int[] {2400, 2500});
// Second time, get the actual delta
SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
reader.readDelta();
- assertArrayEquals(new long[]{3100 * 10000, 2500 * 10000},
+ assertArrayEquals(new long[] {3100 * 10000, 2500 * 10000},
systemServiceCpuThreadTimes.threadCpuTimesUs);
- assertArrayEquals(new long[]{1800 * 10000, 1400 * 10000},
+ assertArrayEquals(new long[] {1800 * 10000, 1400 * 10000},
systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
}
- private void setupDirectory(Path processPath, int[] threadIds, int[] cpuFrequencies,
- int[][] cpuTimes) throws IOException {
+ private void setupDirectory(int pid, int[] threadIds, int[] cpuFrequencies, int[][] cpuTimes,
+ int[] processCpuTimes)
+ throws IOException {
+
+ assertTrue(mProcDirectory.toPath().resolve("self").toFile().mkdirs());
+
+ try (OutputStream timeInStateStream =
+ Files.newOutputStream(
+ mProcDirectory.toPath().resolve("self").resolve("time_in_state"))) {
+ for (int i = 0; i < cpuFrequencies.length; i++) {
+ final String line = cpuFrequencies[i] + " 0\n";
+ timeInStateStream.write(line.getBytes());
+ }
+ }
+
+ Path processPath = mProcDirectory.toPath().resolve(String.valueOf(pid));
// Make /proc/$PID
assertTrue(processPath.toFile().mkdirs());
+ // Write /proc/$PID/stat. Only the fields 14-17 matter.
+ try (OutputStream timeInStateStream = Files.newOutputStream(processPath.resolve("stat"))) {
+ timeInStateStream.write(
+ (pid + " (test) S 4 5 6 7 8 9 10 11 12 13 "
+ + processCpuTimes[0] + " "
+ + processCpuTimes[1] + " "
+ + "16 17 18 19 20 ...").getBytes());
+ }
+
// Make /proc/$PID/task
final Path selfThreadsPath = processPath.resolve("task");
assertTrue(selfThreadsPath.toFile().mkdirs());
- // Make thread directories in reverse order, as they are read in order of creation by
- // CpuThreadProcReader
+ // Make thread directories
for (int i = 0; i < threadIds.length; i++) {
// Make /proc/$PID/task/$TID
final Path threadPath = selfThreadsPath.resolve(String.valueOf(threadIds[i]));
assertTrue(threadPath.toFile().mkdirs());
// Make /proc/$PID/task/$TID/time_in_state
- final OutputStream timeInStateStream =
- Files.newOutputStream(threadPath.resolve("time_in_state"));
- for (int j = 0; j < cpuFrequencies.length; j++) {
- final String line = cpuFrequencies[j] + " " + cpuTimes[i][j] + "\n";
- timeInStateStream.write(line.getBytes());
+ try (OutputStream timeInStateStream =
+ Files.newOutputStream(threadPath.resolve("time_in_state"))) {
+ for (int j = 0; j < cpuFrequencies.length; j++) {
+ final String line = cpuFrequencies[j] + " " + cpuTimes[i][j] + "\n";
+ timeInStateStream.write(line.getBytes());
+ }
}
- timeInStateStream.close();
}
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
index 2eee140b921f..37e1efdecfd1 100644
--- a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
@@ -43,18 +43,18 @@ public class SystemServicePowerCalculatorTest {
private PowerProfile mProfile;
private MockBatteryStatsImpl mMockBatteryStats;
private MockKernelCpuUidFreqTimeReader mMockCpuUidFreqTimeReader;
- private MockServerCpuThreadReader mMockServerCpuThreadReader;
+ private MockSystemServerCpuThreadReader mMockSystemServerCpuThreadReader;
private SystemServicePowerCalculator mSystemServicePowerCalculator;
@Before
public void setUp() throws IOException {
Context context = InstrumentationRegistry.getContext();
mProfile = new PowerProfile(context, true /* forTest */);
- mMockServerCpuThreadReader = new MockServerCpuThreadReader();
+ mMockSystemServerCpuThreadReader = new MockSystemServerCpuThreadReader();
mMockCpuUidFreqTimeReader = new MockKernelCpuUidFreqTimeReader();
mMockBatteryStats = new MockBatteryStatsImpl(new MockClocks())
.setPowerProfile(mProfile)
- .setSystemServerCpuThreadReader(mMockServerCpuThreadReader)
+ .setSystemServerCpuThreadReader(mMockSystemServerCpuThreadReader)
.setKernelCpuUidFreqTimeReader(mMockCpuUidFreqTimeReader)
.setUserInfoProvider(new MockUserInfoProvider());
mMockBatteryStats.getOnBatteryTimeBase().setRunning(true, 0, 0);
@@ -65,12 +65,13 @@ public class SystemServicePowerCalculatorTest {
@Test
public void testCalculateApp() {
// Test Power Profile has two CPU clusters with 3 and 4 speeds, thus 7 freq times total
- mMockServerCpuThreadReader.setThreadTimes(
- new long[]{30000, 40000, 50000, 60000, 70000, 80000, 90000},
- new long[]{20000, 30000, 40000, 50000, 60000, 70000, 80000});
+ mMockSystemServerCpuThreadReader.setCpuTimes(
+ 210000,
+ new long[] {30000, 40000, 50000, 60000, 70000, 80000, 90000},
+ new long[] {20000, 30000, 40000, 50000, 60000, 70000, 80000});
mMockCpuUidFreqTimeReader.setSystemServerCpuTimes(
- new long[]{10000, 20000, 30000, 40000, 50000, 60000, 70000}
+ new long[] {10000, 20000, 30000, 40000, 50000, 60000, 70000}
);
mMockBatteryStats.readKernelUidCpuFreqTimesLocked(null, true, false);
@@ -106,13 +107,13 @@ public class SystemServicePowerCalculatorTest {
mMockBatteryStats.getUidStatsLocked(workSourceUid1), 0);
mSystemServicePowerCalculator.calculateApp(app1, app1.uidObj, 0, 0,
BatteryStats.STATS_SINCE_CHARGED);
- assertEquals(0.27162, app1.systemServiceCpuPowerMah, 0.00001);
+ assertEquals(0.00018958, app1.systemServiceCpuPowerMah, 0.0000001);
BatterySipper app2 = new BatterySipper(BatterySipper.DrainType.APP,
mMockBatteryStats.getUidStatsLocked(workSourceUid2), 0);
mSystemServicePowerCalculator.calculateApp(app2, app2.uidObj, 0, 0,
BatteryStats.STATS_SINCE_CHARGED);
- assertEquals(2.44458, app2.systemServiceCpuPowerMah, 0.00001);
+ assertEquals(0.00170625, app2.systemServiceCpuPowerMah, 0.0000001);
}
private static class MockKernelCpuUidFreqTimeReader extends
@@ -140,14 +141,16 @@ public class SystemServicePowerCalculatorTest {
}
}
- private static class MockServerCpuThreadReader extends SystemServerCpuThreadReader {
+ private static class MockSystemServerCpuThreadReader extends SystemServerCpuThreadReader {
private SystemServiceCpuThreadTimes mThreadTimes = new SystemServiceCpuThreadTimes();
- MockServerCpuThreadReader() {
+ MockSystemServerCpuThreadReader() {
super(null);
}
- public void setThreadTimes(long[] threadCpuTimesUs, long[] binderThreadCpuTimesUs) {
+ public void setCpuTimes(long processCpuTimeUs, long[] threadCpuTimesUs,
+ long[] binderThreadCpuTimesUs) {
+ mThreadTimes.processCpuTimeUs = processCpuTimeUs;
mThreadTimes.threadCpuTimesUs = threadCpuTimesUs;
mThreadTimes.binderThreadCpuTimesUs = binderThreadCpuTimesUs;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index c18e9ce76153..d810fb8257a9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -43,6 +43,7 @@ import android.view.animation.PathInterpolator;
import com.android.internal.view.IInputMethodManager;
import java.util.ArrayList;
+import java.util.concurrent.Executor;
/**
* Manages IME control at the display-level. This occurs when IME comes up in multi-window mode.
@@ -62,15 +63,21 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
private static final int FLOATING_IME_BOTTOM_INSET = -80;
protected final IWindowManager mWmService;
- protected final Handler mHandler;
+ protected final Executor mExecutor;
private final TransactionPool mTransactionPool;
private final DisplayController mDisplayController;
private final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>();
private final ArrayList<ImePositionProcessor> mPositionProcessors = new ArrayList<>();
+ @Deprecated
public DisplayImeController(IWindowManager wmService, DisplayController displayController,
Handler mainHandler, TransactionPool transactionPool) {
- mHandler = mainHandler;
+ this(wmService, displayController, mainHandler::post, transactionPool);
+ }
+
+ public DisplayImeController(IWindowManager wmService, DisplayController displayController,
+ Executor mainExecutor, TransactionPool transactionPool) {
+ mExecutor = mainExecutor;
mWmService = wmService;
mTransactionPool = transactionPool;
mDisplayController = displayController;
@@ -197,7 +204,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
@Override
public void insetsChanged(InsetsState insetsState) {
- mHandler.post(() -> {
+ mExecutor.execute(() -> {
if (mInsetsState.equals(insetsState)) {
return;
}
@@ -224,15 +231,25 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
continue;
}
if (activeControl.getType() == InsetsState.ITYPE_IME) {
- mHandler.post(() -> {
+ mExecutor.execute(() -> {
final Point lastSurfacePosition = mImeSourceControl != null
? mImeSourceControl.getSurfacePosition() : null;
+ final boolean positionChanged =
+ !activeControl.getSurfacePosition().equals(lastSurfacePosition);
+ final boolean leashChanged =
+ !haveSameLeash(mImeSourceControl, activeControl);
mImeSourceControl = activeControl;
- if (!activeControl.getSurfacePosition().equals(lastSurfacePosition)
- && mAnimation != null) {
- startAnimation(mImeShowing, true /* forceRestart */);
- } else if (!mImeShowing) {
- removeImeSurface();
+ if (mAnimation != null) {
+ if (positionChanged) {
+ startAnimation(mImeShowing, true /* forceRestart */);
+ }
+ } else {
+ if (leashChanged) {
+ applyVisibilityToLeash();
+ }
+ if (!mImeShowing) {
+ removeImeSurface();
+ }
}
});
}
@@ -240,13 +257,27 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
}
}
+ private void applyVisibilityToLeash() {
+ SurfaceControl leash = mImeSourceControl.getLeash();
+ if (leash != null) {
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ if (mImeShowing) {
+ t.show(leash);
+ } else {
+ t.hide(leash);
+ }
+ t.apply();
+ mTransactionPool.release(t);
+ }
+ }
+
@Override
public void showInsets(int types, boolean fromIme) {
if ((types & WindowInsets.Type.ime()) == 0) {
return;
}
if (DEBUG) Slog.d(TAG, "Got showInsets for ime");
- mHandler.post(() -> startAnimation(true /* show */, false /* forceRestart */));
+ mExecutor.execute(() -> startAnimation(true /* show */, false /* forceRestart */));
}
@Override
@@ -255,7 +286,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
return;
}
if (DEBUG) Slog.d(TAG, "Got hideInsets for ime");
- mHandler.post(() -> startAnimation(false /* show */, false /* forceRestart */));
+ mExecutor.execute(() -> startAnimation(false /* show */, false /* forceRestart */));
}
@Override
@@ -495,4 +526,20 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
return IInputMethodManager.Stub.asInterface(
ServiceManager.getService(Context.INPUT_METHOD_SERVICE));
}
+
+ private static boolean haveSameLeash(InsetsSourceControl a, InsetsSourceControl b) {
+ if (a == b) {
+ return true;
+ }
+ if (a == null || b == null) {
+ return false;
+ }
+ if (a.getLeash() == b.getLeash()) {
+ return true;
+ }
+ if (a.getLeash() == null || b.getLeash() == null) {
+ return false;
+ }
+ return a.getLeash().isSameSurface(b.getLeash());
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index b4620e27e68c..84b98f9e8047 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -271,14 +271,14 @@ public class SystemWindows {
}
@Override
- public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
+ public int relayout(IWindow window, WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewVisibility, int flags,
long frameNumber, ClientWindowFrames outFrames,
MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
SurfaceControl outBLASTSurfaceControl) {
- int res = super.relayout(window, seq, attrs, requestedWidth, requestedHeight,
+ int res = super.relayout(window, attrs, requestedWidth, requestedHeight,
viewVisibility, flags, frameNumber, outFrames,
mergedConfiguration, outSurfaceControl, outInsetsState,
outActiveControls, outSurfaceSize, outBLASTSurfaceControl);
@@ -365,10 +365,6 @@ public class SystemWindows {
public void updatePointerIcon(float x, float y) {}
@Override
- public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
- int localValue, int localChanges) {}
-
- @Override
public void dispatchWindowShown() {}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
index 9954618134e8..6bc838fcc8be 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -239,9 +239,14 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
throw new RuntimeException("Callers should call scheduleOffset() instead of this "
+ "directly");
}
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
mDisplayAreaMap.forEach(
- (key, leash) -> animateWindows(leash, fromBounds, toBounds, direction,
- durationMs));
+ (key, leash) -> {
+ animateWindows(leash, fromBounds, toBounds, direction,
+ durationMs);
+ wct.setBounds(key.token, toBounds);
+ });
+ applyTransaction(wct);
}
private void resetWindowsOffset() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
index 7c0c738644b7..b6b518d69c55 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
@@ -184,9 +184,8 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback {
mDisplaySize.x, mTutorialAreaHeight, 0, 0,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
- PixelFormat.TRANSLUCENT);
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+ PixelFormat.TRANSLUCENT);
lp.gravity = Gravity.TOP | Gravity.LEFT;
lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
lp.setFitInsetsTypes(0 /* types */);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java
index edbbd69ce0dc..cdb27da7de07 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java
@@ -1319,34 +1319,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mBackground.getRight(), mBackground.getBottom(), Op.UNION);
}
- void onDockedTopTask() {
- mState.animateAfterRecentsDrawn = true;
- startDragging(false /* animate */, false /* touching */);
- updateDockSide();
- mEntranceAnimationRunning = true;
-
- resizeStackSurfaces(calculatePositionForInsetBounds(),
- mSplitLayout.getSnapAlgorithm().getMiddleTarget().position,
- mSplitLayout.getSnapAlgorithm().getMiddleTarget(),
- null /* transaction */);
- }
-
- void onRecentsDrawn() {
- updateDockSide();
- final int position = calculatePositionForInsetBounds();
- if (mState.animateAfterRecentsDrawn) {
- mState.animateAfterRecentsDrawn = false;
-
- mHandler.post(() -> {
- // Delay switching resizing mode because this might cause jank in recents animation
- // that's longer than this animation.
- stopDragging(position, getSnapAlgorithm().getMiddleTarget(),
- mLongPressEntraceAnimDuration, Interpolators.FAST_OUT_SLOW_IN,
- 200 /* endDelay */);
- });
- }
- }
-
void onUndockingTask() {
int dockSide = mSplitLayout.getPrimarySplitSide();
if (inSplitMode()) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index 58106c94a000..985dff20ad32 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -48,14 +48,6 @@ public interface SplitScreen {
/** Switch to minimized state if appropriate. */
void setMinimized(boolean minimized);
- /**
- * Workaround for b/62528361, at the time recents has drawn, it may happen before a
- * configuration change to the Divider, and internally, the event will be posted to the
- * subscriber, or DividerView, which has been removed and prevented from resizing. Instead,
- * register the event handler here and proxy the event to the current DividerView.
- */
- void onRecentsDrawn();
-
/** Called when there's an activity forced resizable. */
void onActivityForcedResizable(String packageName, int taskId, int reason);
@@ -68,9 +60,6 @@ public interface SplitScreen {
/** Called when there's a task undocking. */
void onUndockingTask();
- /** Called when top task docked. */
- void onDockedTopTask();
-
/** Called when app transition finished. */
void onAppTransitionFinished();
@@ -85,4 +74,13 @@ public interface SplitScreen {
/** @return the container token for the secondary split root task. */
WindowContainerToken getSecondaryRoot();
+
+ /**
+ * Splits the primary task if feasible, this is to preserve legacy way to toggle split screen.
+ * Like triggering split screen through long pressing recents app button or through
+ * {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN}.
+ *
+ * @return {@code true} if it successes to split the primary task.
+ */
+ boolean splitPrimaryTask();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index ce49dd9d1eb4..43e4d62baaf6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -16,19 +16,25 @@
package com.android.wm.shell.splitscreen;
+import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.view.Display.DEFAULT_DISPLAY;
+import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Handler;
+import android.os.RemoteException;
import android.provider.Settings;
import android.util.Slog;
import android.view.LayoutInflater;
import android.view.View;
+import android.widget.Toast;
import android.window.TaskOrganizer;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -47,6 +53,7 @@ import com.android.wm.shell.common.TransactionPool;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@@ -57,7 +64,7 @@ public class SplitScreenController implements SplitScreen,
DisplayController.OnDisplaysChangedListener {
static final boolean DEBUG = false;
- private static final String TAG = "Divider";
+ private static final String TAG = "SplitScreenCtrl";
private static final int DEFAULT_APP_TRANSITION_DURATION = 336;
private final Context mContext;
@@ -157,12 +164,12 @@ public class SplitScreenController implements SplitScreen,
// Don't initialize the divider or anything until we get the default display.
}
- /** Returns {@code true} if split screen is supported on the device. */
+ @Override
public boolean isSplitScreenSupported() {
return mSplits.isSplitScreenSupported();
}
- /** Called when keyguard showing state changed. */
+ @Override
public void onKeyguardVisibilityChanged(boolean showing) {
if (!isSplitActive() || mView == null) {
return;
@@ -229,21 +236,22 @@ public class SplitScreenController implements SplitScreen,
mHandler.post(task);
}
- /** Returns {@link DividerView}. */
+ @Override
public DividerView getDividerView() {
return mView;
}
- /** Returns {@code true} if one of the split screen is in minimized mode. */
+ @Override
public boolean isMinimized() {
return mMinimized;
}
+ @Override
public boolean isHomeStackResizable() {
return mHomeStackResizable;
}
- /** Returns {@code true} if the divider is visible. */
+ @Override
public boolean isDividerVisible() {
return mView != null && mView.getVisibility() == View.VISIBLE;
}
@@ -328,7 +336,7 @@ public class SplitScreenController implements SplitScreen,
}
}
- /** Switch to minimized state if appropriate. */
+ @Override
public void setMinimized(final boolean minimized) {
if (DEBUG) Slog.d(TAG, "posting ext setMinimized " + minimized + " vis:" + mVisible);
mHandler.post(() -> {
@@ -392,48 +400,29 @@ public class SplitScreenController implements SplitScreen,
mWindowManager.setTouchable(!mAdjustedForIme);
}
- /**
- * Workaround for b/62528361, at the time recents has drawn, it may happen before a
- * configuration change to the Divider, and internally, the event will be posted to the
- * subscriber, or DividerView, which has been removed and prevented from resizing. Instead,
- * register the event handler here and proxy the event to the current DividerView.
- */
- public void onRecentsDrawn() {
- if (mView != null) {
- mView.onRecentsDrawn();
- }
- }
-
- /** Called when there's an activity forced resizable. */
+ @Override
public void onActivityForcedResizable(String packageName, int taskId, int reason) {
mForcedResizableController.activityForcedResizable(packageName, taskId, reason);
}
- /** Called when there's an activity dismissing split screen. */
+ @Override
public void onActivityDismissingSplitScreen() {
mForcedResizableController.activityDismissingSplitScreen();
}
- /** Called when there's an activity launch on secondary display failed. */
+ @Override
public void onActivityLaunchOnSecondaryDisplayFailed() {
mForcedResizableController.activityLaunchOnSecondaryDisplayFailed();
}
- /** Called when there's a task undocking. */
+ @Override
public void onUndockingTask() {
if (mView != null) {
mView.onUndockingTask();
}
}
- /** Called when top task docked. */
- public void onDockedTopTask() {
- if (mView != null) {
- mView.onDockedTopTask();
- }
- }
-
- /** Called when app transition finished. */
+ @Override
public void onAppTransitionFinished() {
if (mView == null) {
return;
@@ -441,7 +430,7 @@ public class SplitScreenController implements SplitScreen,
mForcedResizableController.onAppTransitionFinished();
}
- /** Dumps current status of Split Screen. */
+ @Override
public void dump(PrintWriter pw) {
pw.print(" mVisible="); pw.println(mVisible);
pw.print(" mMinimized="); pw.println(mMinimized);
@@ -458,7 +447,7 @@ public class SplitScreenController implements SplitScreen,
return (long) (transitionDuration * transitionScale);
}
- /** Registers listener that gets called whenever the existence of the divider changes. */
+ @Override
public void registerInSplitScreenListener(Consumer<Boolean> listener) {
listener.accept(isDividerVisible());
synchronized (mDockedStackExistsListeners) {
@@ -473,6 +462,42 @@ public class SplitScreenController implements SplitScreen,
}
}
+ @Override
+ public boolean splitPrimaryTask() {
+ try {
+ if (ActivityTaskManager.getService().getLockTaskModeState() == LOCK_TASK_MODE_PINNED
+ || isSplitActive()) {
+ return false;
+ }
+
+ // Try fetching the top running task.
+ final List<RunningTaskInfo> runningTasks =
+ ActivityTaskManager.getService().getTasks(1 /* maxNum */);
+ if (runningTasks == null || runningTasks.isEmpty()) {
+ return false;
+ }
+ // Note: The set of running tasks from the system is ordered by recency.
+ final RunningTaskInfo topRunningTask = runningTasks.get(0);
+
+ final int activityType = topRunningTask.configuration.windowConfiguration
+ .getActivityType();
+ if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
+ return false;
+ }
+
+ if (!topRunningTask.supportsSplitScreenMultiWindow) {
+ Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text,
+ Toast.LENGTH_SHORT).show();
+ return false;
+ }
+
+ return ActivityTaskManager.getService().setTaskWindowingModeSplitScreenPrimary(
+ topRunningTask.taskId, true /* onTop */);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
/** Notifies the bounds of split screen changed. */
void notifyBoundsChanged(Rect secondaryWindowBounds, Rect secondaryWindowInsets) {
synchronized (mBoundsChangedListeners) {
@@ -532,7 +557,7 @@ public class SplitScreenController implements SplitScreen,
return mWindowManagerProxy;
}
- /** @return the container token for the secondary split root task. */
+ @Override
public WindowContainerToken getSecondaryRoot() {
if (mSplits == null || mSplits.mSecondary == null) {
return null;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
new file mode 100644
index 000000000000..080cddc58a09
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.common;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.InsetsState.ITYPE_IME;
+import static android.view.Surface.ROTATION_0;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.graphics.Point;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+import android.view.SurfaceControl;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.view.IInputMethodManager;
+
+import org.junit.Before;
+import org.junit.Test;
+
+@SmallTest
+public class DisplayImeControllerTest {
+
+ private SurfaceControl.Transaction mT;
+ private DisplayImeController.PerDisplay mPerDisplay;
+ private IInputMethodManager mMock;
+
+ @Before
+ public void setUp() throws Exception {
+ mT = mock(SurfaceControl.Transaction.class);
+ mMock = mock(IInputMethodManager.class);
+ mPerDisplay = new DisplayImeController(null, null, Runnable::run, new TransactionPool() {
+ @Override
+ public SurfaceControl.Transaction acquire() {
+ return mT;
+ }
+
+ @Override
+ public void release(SurfaceControl.Transaction t) {
+ }
+ }) {
+ @Override
+ public IInputMethodManager getImms() {
+ return mMock;
+ }
+ }.new PerDisplay(DEFAULT_DISPLAY, ROTATION_0);
+ }
+
+ @Test
+ public void reappliesVisibilityToChangedLeash() {
+ verifyZeroInteractions(mT);
+
+ mPerDisplay.mImeShowing = false;
+ mPerDisplay.insetsControlChanged(new InsetsState(), new InsetsSourceControl[] {
+ new InsetsSourceControl(ITYPE_IME, mock(SurfaceControl.class), new Point(0, 0))
+ });
+
+ verify(mT).hide(any());
+
+ mPerDisplay.mImeShowing = true;
+ mPerDisplay.insetsControlChanged(new InsetsState(), new InsetsSourceControl[] {
+ new InsetsSourceControl(ITYPE_IME, mock(SurfaceControl.class), new Point(0, 0))
+ });
+
+ verify(mT).show(any());
+ }
+}
diff --git a/libs/androidfw/include/androidfw/CursorWindow.h b/libs/androidfw/include/androidfw/CursorWindow.h
index 73c76f0bcb5b..0bee60929cc9 100644
--- a/libs/androidfw/include/androidfw/CursorWindow.h
+++ b/libs/androidfw/include/androidfw/CursorWindow.h
@@ -170,7 +170,7 @@ private:
Header* mHeader;
inline void* offsetToPtr(uint32_t offset, uint32_t bufferSize = 0) {
- if (offset >= mSize) {
+ if (offset > mSize) {
ALOGE("Offset %" PRIu32 " out of bounds, max value %zu", offset, mSize);
return NULL;
}
diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java
index 523a072b957a..dbf4ad0b14f9 100644
--- a/media/java/android/media/MediaMetadata.java
+++ b/media/java/android/media/MediaMetadata.java
@@ -18,13 +18,13 @@ package android.media;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.StringDef;
-import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.browse.MediaBrowser;
import android.media.session.MediaController;
+import android.media.session.MediaSession;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
@@ -417,14 +417,17 @@ public final class MediaMetadata implements Parcelable {
}
private final Bundle mBundle;
+ private final int mBitmapDimensionLimit;
private MediaDescription mDescription;
- private MediaMetadata(Bundle bundle) {
+ private MediaMetadata(Bundle bundle, int bitmapDimensionLimit) {
mBundle = new Bundle(bundle);
+ mBitmapDimensionLimit = bitmapDimensionLimit;
}
private MediaMetadata(Parcel in) {
mBundle = in.readBundle();
+ mBitmapDimensionLimit = Math.max(in.readInt(), 0);
}
/**
@@ -513,6 +516,22 @@ public final class MediaMetadata implements Parcelable {
return bmp;
}
+ /**
+ * Gets the width/height limit (in pixels) for the bitmaps when this metadata was created.
+ * This method returns a positive value or zero.
+ * <p>
+ * If it returns a positive value, then all the bitmaps in this metadata has width/height
+ * not greater than this limit. Bitmaps may have been scaled down according to the limit.
+ * <p>
+ * If it returns zero, then no scaling down was applied to the bitmaps when this metadata
+ * was created.
+ *
+ * @see Builder#setBitmapDimensionLimit(int)
+ */
+ public @IntRange(from = 0) int getBitmapDimensionLimit() {
+ return mBitmapDimensionLimit;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -521,6 +540,7 @@ public final class MediaMetadata implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeBundle(mBundle);
+ dest.writeInt(mBitmapDimensionLimit);
}
/**
@@ -718,6 +738,7 @@ public final class MediaMetadata implements Parcelable {
*/
public static final class Builder {
private final Bundle mBundle;
+ private int mBitmapDimensionLimit;
/**
* Create an empty Builder. Any field that should be included in the
@@ -736,30 +757,7 @@ public final class MediaMetadata implements Parcelable {
*/
public Builder(MediaMetadata source) {
mBundle = new Bundle(source.mBundle);
- }
-
- /**
- * Create a Builder using a {@link MediaMetadata} instance to set
- * initial values, but replace bitmaps with a scaled down copy if their width (or height)
- * is larger than maxBitmapSize.
- *
- * @param source The original metadata to copy.
- * @param maxBitmapSize The maximum height/width for bitmaps contained
- * in the metadata.
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public Builder(@NonNull MediaMetadata source, @IntRange(from = 1) int maxBitmapSize) {
- this(source);
- for (String key : mBundle.keySet()) {
- Object value = mBundle.get(key);
- if (value != null && value instanceof Bitmap) {
- Bitmap bmp = (Bitmap) value;
- if (bmp.getHeight() > maxBitmapSize || bmp.getWidth() > maxBitmapSize) {
- putBitmap(key, scaleBitmap(bmp, maxBitmapSize));
- }
- }
- }
+ mBitmapDimensionLimit = source.mBitmapDimensionLimit;
}
/**
@@ -902,9 +900,9 @@ public final class MediaMetadata implements Parcelable {
* <li>{@link #METADATA_KEY_DISPLAY_ICON}</li>
* </ul>
* <p>
- * Large bitmaps may be scaled down by the system when
- * {@link android.media.session.MediaSession#setMetadata} is called.
- * To pass full resolution images {@link Uri Uris} should be used with
+ * Large bitmaps may be scaled down by the system with
+ * {@link Builder#setBitmapDimensionLimit(int)} when {@link MediaSession#setMetadata}
+ * is called. To pass full resolution images {@link Uri Uris} should be used with
* {@link #putString}.
*
* @param key The key for referencing this value
@@ -923,18 +921,46 @@ public final class MediaMetadata implements Parcelable {
}
/**
+ * Sets the maximum width/height (in pixels) for the bitmaps in the metadata.
+ * Bitmaps will be replaced with scaled down copies if their width (or height) is
+ * larger than {@code bitmapDimensionLimit}.
+ * <p>
+ * In order to unset the limit, pass zero as {@code bitmapDimensionLimit}.
+ *
+ * @param bitmapDimensionLimit The maximum width/height (in pixels) for bitmaps
+ * contained in the metadata. Pass {@code 0} to unset the limit.
+ */
+ @NonNull
+ public Builder setBitmapDimensionLimit(int bitmapDimensionLimit) {
+ mBitmapDimensionLimit = Math.max(bitmapDimensionLimit, 0);
+ return this;
+ }
+
+ /**
* Creates a {@link MediaMetadata} instance with the specified fields.
*
* @return The new MediaMetadata instance
*/
public MediaMetadata build() {
- return new MediaMetadata(mBundle);
+ if (mBitmapDimensionLimit > 0) {
+ for (String key : mBundle.keySet()) {
+ Object value = mBundle.get(key);
+ if (value instanceof Bitmap) {
+ Bitmap bmp = (Bitmap) value;
+ if (bmp.getHeight() > mBitmapDimensionLimit
+ || bmp.getWidth() > mBitmapDimensionLimit) {
+ putBitmap(key, scaleBitmap(bmp, mBitmapDimensionLimit));
+ }
+ }
+ }
+ }
+ return new MediaMetadata(mBundle, mBitmapDimensionLimit);
}
- private Bitmap scaleBitmap(Bitmap bmp, int maxSize) {
- float maxSizeF = maxSize;
- float widthScale = maxSizeF / bmp.getWidth();
- float heightScale = maxSizeF / bmp.getHeight();
+ private Bitmap scaleBitmap(Bitmap bmp, int maxDimension) {
+ float maxDimensionF = maxDimension;
+ float widthScale = maxDimensionF / bmp.getWidth();
+ float heightScale = maxDimensionF / bmp.getHeight();
float scale = Math.min(widthScale, heightScale);
int height = (int) (bmp.getHeight() * scale);
int width = (int) (bmp.getWidth() * scale);
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index d35bc4176cb3..d02b49697821 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -372,7 +372,7 @@ public class Ringtone {
AudioAttributes.toLegacyStreamType(mAudioAttributes)) != 0) {
startLocalPlayer();
}
- } else if (mAllowRemote && (mRemotePlayer != null)) {
+ } else if (mAllowRemote && (mRemotePlayer != null) && (mUri != null)) {
final Uri canonicalUri = mUri.getCanonicalUri();
final boolean looping;
final float volume;
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 8deb0c4451ea..c75296c73a90 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -1130,11 +1130,13 @@ public class RingtoneManager {
// Try finding the scanned ringtone
final String filename = getDefaultRingtoneFilename(type);
+ final String whichAudio = getQueryStringForType(type);
+ final String where = MediaColumns.DISPLAY_NAME + "=? AND " + whichAudio + "=?";
final Uri baseUri = MediaStore.Audio.Media.INTERNAL_CONTENT_URI;
try (Cursor cursor = context.getContentResolver().query(baseUri,
new String[] { MediaColumns._ID },
- MediaColumns.DISPLAY_NAME + "=?",
- new String[] { filename }, null)) {
+ where,
+ new String[] { filename, "1" }, null)) {
if (cursor.moveToFirst()) {
final Uri ringtoneUri = context.getContentResolver().canonicalizeOrElse(
ContentUris.withAppendedId(baseUri, cursor.getLong(0)));
@@ -1162,4 +1164,13 @@ public class RingtoneManager {
default: throw new IllegalArgumentException();
}
}
+
+ private static String getQueryStringForType(int type) {
+ switch (type) {
+ case TYPE_RINGTONE: return MediaStore.Audio.AudioColumns.IS_RINGTONE;
+ case TYPE_NOTIFICATION: return MediaStore.Audio.AudioColumns.IS_NOTIFICATION;
+ case TYPE_ALARM: return MediaStore.Audio.AudioColumns.IS_ALARM;
+ default: throw new IllegalArgumentException();
+ }
+ }
}
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 624607b61b8f..e17e069d61d0 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -464,7 +464,9 @@ public final class MediaSession {
int fields = 0;
MediaDescription description = null;
if (metadata != null) {
- metadata = (new MediaMetadata.Builder(metadata, mMaxBitmapSize)).build();
+ metadata = new MediaMetadata.Builder(metadata)
+ .setBitmapDimensionLimit(mMaxBitmapSize)
+ .build();
if (metadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
duration = metadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
}
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index dd06ae032979..ff954690501c 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -6138,6 +6138,7 @@ package android.app {
field @NonNull public static final android.os.Parcelable.Creator<android.app.PendingIntent> CREATOR;
field public static final int FLAG_CANCEL_CURRENT = 268435456; // 0x10000000
field public static final int FLAG_IMMUTABLE = 67108864; // 0x4000000
+ field public static final int FLAG_MUTABLE = 33554432; // 0x2000000
field public static final int FLAG_NO_CREATE = 536870912; // 0x20000000
field public static final int FLAG_ONE_SHOT = 1073741824; // 0x40000000
field public static final int FLAG_UPDATE_CURRENT = 134217728; // 0x8000000
@@ -26317,6 +26318,7 @@ package android.media {
method public boolean containsKey(String);
method public int describeContents();
method public android.graphics.Bitmap getBitmap(String);
+ method @IntRange(from=0) public int getBitmapDimensionLimit();
method @NonNull public android.media.MediaDescription getDescription();
method public long getLong(String);
method public android.media.Rating getRating(String);
@@ -26366,6 +26368,7 @@ package android.media {
method public android.media.MediaMetadata.Builder putRating(String, android.media.Rating);
method public android.media.MediaMetadata.Builder putString(String, String);
method public android.media.MediaMetadata.Builder putText(String, CharSequence);
+ method @NonNull public android.media.MediaMetadata.Builder setBitmapDimensionLimit(int);
}
@Deprecated public abstract class MediaMetadataEditor {
@@ -44934,6 +44937,7 @@ package android.telephony {
field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
field public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL = "carrier_supports_ss_over_ut_bool";
field public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
+ field public static final String KEY_CARRIER_USSD_METHOD_INT = "carrier_ussd_method_int";
field public static final String KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL = "carrier_ut_provisioning_required_bool";
field public static final String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
field public static final String KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL = "carrier_volte_override_wfc_provisioning_bool";
@@ -45128,6 +45132,10 @@ package android.telephony {
field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
field public static final int SERVICE_CLASS_NONE = 0; // 0x0
field public static final int SERVICE_CLASS_VOICE = 1; // 0x1
+ field public static final int USSD_OVER_CS_ONLY = 2; // 0x2
+ field public static final int USSD_OVER_CS_PREFERRED = 0; // 0x0
+ field public static final int USSD_OVER_IMS_ONLY = 3; // 0x3
+ field public static final int USSD_OVER_IMS_PREFERRED = 1; // 0x1
}
public static final class CarrierConfigManager.Apn {
@@ -51774,6 +51782,33 @@ package android.view {
field public int toolType;
}
+ public interface OnReceiveContentCallback<T extends android.view.View> {
+ method @NonNull public java.util.Set<java.lang.String> getSupportedMimeTypes(@NonNull T);
+ method public boolean onReceiveContent(@NonNull T, @NonNull android.view.OnReceiveContentCallback.Payload);
+ }
+
+ public static final class OnReceiveContentCallback.Payload {
+ method @NonNull public android.content.ClipData getClip();
+ method @Nullable public android.os.Bundle getExtras();
+ method public int getFlags();
+ method @Nullable public android.net.Uri getLinkUri();
+ method public int getSource();
+ field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
+ field public static final int SOURCE_AUTOFILL = 3; // 0x3
+ field public static final int SOURCE_CLIPBOARD = 0; // 0x0
+ field public static final int SOURCE_DRAG_AND_DROP = 2; // 0x2
+ field public static final int SOURCE_INPUT_METHOD = 1; // 0x1
+ field public static final int SOURCE_PROCESS_TEXT = 4; // 0x4
+ }
+
+ public static final class OnReceiveContentCallback.Payload.Builder {
+ ctor public OnReceiveContentCallback.Payload.Builder(@NonNull android.content.ClipData, int);
+ method @NonNull public android.view.OnReceiveContentCallback.Payload build();
+ method @NonNull public android.view.OnReceiveContentCallback.Payload.Builder setExtras(@Nullable android.os.Bundle);
+ method @NonNull public android.view.OnReceiveContentCallback.Payload.Builder setFlags(int);
+ method @NonNull public android.view.OnReceiveContentCallback.Payload.Builder setLinkUri(@Nullable android.net.Uri);
+ }
+
public abstract class OrientationEventListener {
ctor public OrientationEventListener(android.content.Context);
ctor public OrientationEventListener(android.content.Context, int);
@@ -52325,6 +52360,7 @@ package android.view {
method @IdRes public int getNextFocusRightId();
method @IdRes public int getNextFocusUpId();
method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
+ method @Nullable public android.view.OnReceiveContentCallback<? extends android.view.View> getOnReceiveContentCallback();
method @ColorInt public int getOutlineAmbientShadowColor();
method public android.view.ViewOutlineProvider getOutlineProvider();
method @ColorInt public int getOutlineSpotShadowColor();
@@ -52676,6 +52712,7 @@ package android.view {
method public void setOnHoverListener(android.view.View.OnHoverListener);
method public void setOnKeyListener(android.view.View.OnKeyListener);
method public void setOnLongClickListener(@Nullable android.view.View.OnLongClickListener);
+ method public void setOnReceiveContentCallback(@Nullable android.view.OnReceiveContentCallback<? extends android.view.View>);
method public void setOnScrollChangeListener(android.view.View.OnScrollChangeListener);
method @Deprecated public void setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener);
method public void setOnTouchListener(android.view.View.OnTouchListener);
@@ -58938,17 +58975,6 @@ package android.widget {
method public android.view.View newGroupView(android.content.Context, android.database.Cursor, boolean, android.view.ViewGroup);
}
- public interface RichContentReceiver<T extends android.view.View> {
- method @NonNull public java.util.Set<java.lang.String> getSupportedMimeTypes();
- method public boolean onReceive(@NonNull T, @NonNull android.content.ClipData, int, int);
- field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
- field public static final int SOURCE_AUTOFILL = 3; // 0x3
- field public static final int SOURCE_CLIPBOARD = 0; // 0x0
- field public static final int SOURCE_DRAG_AND_DROP = 2; // 0x2
- field public static final int SOURCE_INPUT_METHOD = 1; // 0x1
- field public static final int SOURCE_PROCESS_TEXT = 4; // 0x4
- }
-
public class ScrollView extends android.widget.FrameLayout {
ctor public ScrollView(android.content.Context);
ctor public ScrollView(android.content.Context, android.util.AttributeSet);
@@ -59503,10 +59529,10 @@ package android.widget {
method public int getMinWidth();
method public final android.text.method.MovementMethod getMovementMethod();
method public int getOffsetForPosition(float, float);
+ method @Nullable public android.view.OnReceiveContentCallback<android.widget.TextView> getOnReceiveContentCallback();
method public android.text.TextPaint getPaint();
method public int getPaintFlags();
method public String getPrivateImeOptions();
- method @NonNull public android.widget.RichContentReceiver<android.widget.TextView> getRichContentReceiver();
method public int getSelectionEnd();
method public int getSelectionStart();
method @ColorInt public int getShadowColor();
@@ -59634,7 +59660,6 @@ package android.widget {
method public void setPaintFlags(int);
method public void setPrivateImeOptions(String);
method public void setRawInputType(int);
- method public void setRichContentReceiver(@NonNull android.widget.RichContentReceiver<android.widget.TextView>);
method public void setScroller(android.widget.Scroller);
method public void setSelectAllOnFocus(boolean);
method public void setShadowLayer(float, float, float, int);
@@ -59675,7 +59700,6 @@ package android.widget {
method public void setWidth(int);
field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0
field public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1; // 0x1
- field @NonNull public static final android.widget.RichContentReceiver<android.widget.TextView> DEFAULT_RICH_CONTENT_RECEIVER;
}
public enum TextView.BufferType {
@@ -59692,6 +59716,12 @@ package android.widget {
field @NonNull public static final android.os.Parcelable.Creator<android.widget.TextView.SavedState> CREATOR;
}
+ public class TextViewOnReceiveContentCallback implements android.view.OnReceiveContentCallback<android.widget.TextView> {
+ ctor public TextViewOnReceiveContentCallback();
+ method @NonNull public java.util.Set<java.lang.String> getSupportedMimeTypes(@NonNull android.widget.TextView);
+ method public boolean onReceiveContent(@NonNull android.widget.TextView, @NonNull android.view.OnReceiveContentCallback.Payload);
+ }
+
public interface ThemedSpinnerAdapter extends android.widget.SpinnerAdapter {
method @Nullable public android.content.res.Resources.Theme getDropDownViewTheme();
method public void setDropDownViewTheme(@Nullable android.content.res.Resources.Theme);
diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt
index 44b0ab8de66a..11cd6a93910e 100644
--- a/non-updatable-api/module-lib-current.txt
+++ b/non-updatable-api/module-lib-current.txt
@@ -53,10 +53,6 @@ package android.media {
field public static final int FLAG_FROM_KEY = 4096; // 0x1000
}
- public static final class MediaMetadata.Builder {
- ctor public MediaMetadata.Builder(@NonNull android.media.MediaMetadata, @IntRange(from=1) int);
- }
-
}
package android.media.session {
diff --git a/packages/CarSystemUI/res/drawable/car_ic_settings_icon.xml b/packages/CarSystemUI/res/drawable/car_ic_settings_icon.xml
new file mode 100644
index 000000000000..147f5397361e
--- /dev/null
+++ b/packages/CarSystemUI/res/drawable/car_ic_settings_icon.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@*android:dimen/status_bar_system_icon_size"
+ android:height="@*android:dimen/status_bar_system_icon_size"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@color/system_bar_icon_color"
+ android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4C9.75,2 9.54,2.18 9.51,2.42L9.13,5.07C8.52,5.32 7.96,5.66 7.44,6.05l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46C2.21,8.95 2.27,9.22 2.46,9.37l2.11,1.65C4.53,11.34 4.5,11.67 4.5,12s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65C9.54,21.82 9.75,22 10,22h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64L19.43,12.98zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5s3.5,1.57 3.5,3.5S13.93,15.5 12,15.5z"/>
+</vector>
diff --git a/packages/CarSystemUI/res/drawable/car_ic_user_icon.xml b/packages/CarSystemUI/res/drawable/car_ic_user_icon.xml
index 1195d05da228..270d932714f3 100644
--- a/packages/CarSystemUI/res/drawable/car_ic_user_icon.xml
+++ b/packages/CarSystemUI/res/drawable/car_ic_user_icon.xml
@@ -21,5 +21,5 @@
android:viewportHeight="24">
<path
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"
- android:fillColor="@color/system_bar_user_icon_color"/>
+ android:fillColor="@color/system_bar_icon_color"/>
</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
index 07c11c76a4f2..7994b19242cd 100644
--- a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
@@ -36,6 +36,7 @@
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_marginTop="@dimen/car_padding_2"
+ android:layout_marginStart="@dimen/car_padding_2"
android:layout_centerVertical="true"
android:gravity="center_vertical"
>
@@ -44,7 +45,6 @@
android:layout_height="match_parent"
android:background="@drawable/system_bar_background_pill"
android:layout_weight="1"
- android:layout_marginStart="@dimen/car_padding_2"
android:gravity="center_vertical"
systemui:intent="intent:#Intent;component=com.android.car.settings/.common.CarSettingActivities$QuickSettingActivity;launchFlags=0x24000000;end">
@@ -53,6 +53,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:layout_marginStart="@dimen/car_padding_2"
+ android:layout_marginEnd="@dimen/car_padding_2"
android:gravity="center_vertical"
/>
</com.android.systemui.car.navigationbar.CarNavigationButton>
diff --git a/packages/CarSystemUI/res/layout/system_icons.xml b/packages/CarSystemUI/res/layout/system_icons.xml
index 5c06075e8617..f6ffcc8c16f0 100644
--- a/packages/CarSystemUI/res/layout/system_icons.xml
+++ b/packages/CarSystemUI/res/layout/system_icons.xml
@@ -20,16 +20,24 @@
android:id="@+id/system_icons"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:gravity="center_vertical">
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
<com.android.systemui.statusbar.phone.StatusIconContainer
android:id="@+id/statusIcons"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
- android:padding="10dp"
android:scaleType="fitCenter"
android:gravity="center_vertical"
android:orientation="horizontal"
/>
+
+ <ImageView
+ android:id="@+id/settingsIcon"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginStart="@dimen/car_padding_2"
+ android:src="@drawable/car_ic_settings_icon"
+ />
</LinearLayout> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/values/colors.xml b/packages/CarSystemUI/res/values/colors.xml
index 6fe5004c459f..0181b9a39aea 100644
--- a/packages/CarSystemUI/res/values/colors.xml
+++ b/packages/CarSystemUI/res/values/colors.xml
@@ -33,7 +33,7 @@
<!-- colors for status bar -->
<color name="system_bar_background_pill_color">#282A2D</color>
- <color name="system_bar_user_icon_color">#FFFFFF</color>
+ <color name="system_bar_icon_color">#FFFFFF</color>
<color name="system_bar_text_color">#FFFFFF</color>
<color name="status_bar_background_color">#33000000</color>
<drawable name="system_bar_background">@color/status_bar_background_color</drawable>
diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml
index fe060ac8e707..86bfa751d085 100644
--- a/packages/CarSystemUI/res/values/dimens.xml
+++ b/packages/CarSystemUI/res/values/dimens.xml
@@ -46,6 +46,10 @@
in frameworks/base/core package and thus will have no effect if
set here. See car_product overlay for car specific defaults-->
+ <!-- Overrides the space between each status icon in the system bar -->
+ <dimen name="status_bar_system_icon_spacing">16dp</dimen>
+ <!-- Overrides the size of the network signal icon -->
+ <dimen name="signal_icon_size">32dp</dimen>
<dimen name="system_bar_user_icon_padding">16dp</dimen>
<dimen name="system_bar_user_icon_drawing_size">36dp</dimen>
<!-- Padding on either side of the group of all system bar buttons -->
diff --git a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
index b113d29f00e6..f2ca4956be07 100644
--- a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
@@ -50,6 +50,7 @@ public class DisplaySystemBarsController extends DisplayImeController {
private final Context mContext;
private final DisplayController mDisplayController;
+ private final Handler mHandler;
private SparseArray<PerDisplay> mPerDisplaySparseArray;
public DisplaySystemBarsController(
@@ -58,9 +59,10 @@ public class DisplaySystemBarsController extends DisplayImeController {
DisplayController displayController,
@Main Handler mainHandler,
TransactionPool transactionPool) {
- super(wmService, displayController, mainHandler, transactionPool);
+ super(wmService, displayController, (r) -> mainHandler.post(r), transactionPool);
mContext = context;
mDisplayController = displayController;
+ mHandler = mainHandler;
}
@Override
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 9788b30f82c4..08109798841f 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -437,6 +437,7 @@ public class SettingsBackupTest {
Settings.Global.SHOW_MUTE_IN_CRASH_DIALOG,
Settings.Global.SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED,
Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS,
+ Settings.Global.SHOW_PEOPLE_SPACE,
Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG,
Settings.Global.SHOW_TEMPERATURE_WARNING,
Settings.Global.SHOW_USB_TEMPERATURE_ALARM,
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index ce427cbe776b..0eac4add7b09 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -511,14 +511,14 @@ public class BugreportProgressService extends Service {
}
if (msg.what != MSG_SERVICE_COMMAND) {
- // Sanity check.
+ // Confidence check.
Log.e(TAG, "Invalid message type: " + msg.what);
return;
}
// At this point it's handling onStartCommand(), with the intent passed as an Extra.
if (!(msg.obj instanceof Intent)) {
- // Sanity check.
+ // Confidence check.
Log.wtf(TAG, "handleMessage(): invalid msg.obj type: " + msg.obj);
return;
}
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index cd3cad1d6351..3b02e3b46557 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -466,7 +466,7 @@ public class BugreportReceiverTest {
// Clear properties
mContext.getSharedPreferences(PREFS_BUGREPORT, Context.MODE_PRIVATE)
.edit().clear().commit();
- // Sanity check...
+ // Confidence check...
assertEquals("Did not reset properties", STATE_UNKNOWN,
getWarningState(mContext, STATE_UNKNOWN));
} else {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index cffc10f65f1e..ee05c6cf4c47 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -373,19 +373,6 @@ public class ActivityManagerWrapper {
}
/**
- * Moves an already resumed task to the side of the screen to initiate split screen.
- */
- public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode,
- Rect initialBounds) {
- try {
- return ActivityTaskManager.getService().setTaskWindowingModeSplitScreenPrimary(taskId,
- true /* onTop */);
- } catch (RemoteException e) {
- return false;
- }
- }
-
- /**
* Registers a task stack listener with the system.
* This should be called on the main thread.
*/
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
index 2985a61dec9e..86129e0e204e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
@@ -47,6 +47,7 @@ public class SyncRtSurfaceTransactionApplierCompat {
public static final int FLAG_BACKGROUND_BLUR_RADIUS = 1 << 5;
public static final int FLAG_VISIBILITY = 1 << 6;
public static final int FLAG_RELATIVE_LAYER = 1 << 7;
+ public static final int FLAG_SHADOW_RADIUS = 1 << 8;
private static final int MSG_UPDATE_SEQUENCE_NUMBER = 0;
@@ -196,6 +197,7 @@ public class SyncRtSurfaceTransactionApplierCompat {
SurfaceControl relativeTo;
int relativeLayer;
boolean visible;
+ float shadowRadius;
/**
* @param surface The surface to modify.
@@ -274,6 +276,16 @@ public class SyncRtSurfaceTransactionApplierCompat {
}
/**
+ * @param radius the Radius for the shadows to apply to the surface.
+ * @return this Builder
+ */
+ public Builder withShadowRadius(float radius) {
+ this.shadowRadius = radius;
+ flags |= FLAG_SHADOW_RADIUS;
+ return this;
+ }
+
+ /**
* @param radius the Radius for blur to apply to the background surfaces.
* @return this Builder
*/
@@ -298,31 +310,14 @@ public class SyncRtSurfaceTransactionApplierCompat {
*/
public SurfaceParams build() {
return new SurfaceParams(surface, flags, alpha, matrix, windowCrop, layer,
- relativeTo, relativeLayer, cornerRadius, backgroundBlurRadius, visible);
+ relativeTo, relativeLayer, cornerRadius, backgroundBlurRadius, visible,
+ shadowRadius);
}
}
- /**
- * Constructs surface parameters to be applied when the current view state gets pushed to
- * RenderThread.
- *
- * @param surface The surface to modify.
- * @param alpha Alpha to apply.
- * @param matrix Matrix to apply.
- * @param windowCrop Crop to apply, only applied if not {@code null}
- */
- public SurfaceParams(SurfaceControlCompat surface, float alpha, Matrix matrix,
- Rect windowCrop, int layer, SurfaceControl relativeTo, int relativeLayer,
- float cornerRadius) {
- this(surface.mSurfaceControl,
- FLAG_ALL & ~(FLAG_VISIBILITY | FLAG_BACKGROUND_BLUR_RADIUS), alpha,
- matrix, windowCrop, layer, relativeTo, relativeLayer, cornerRadius,
- 0 /* backgroundBlurRadius */, true);
- }
-
private SurfaceParams(SurfaceControl surface, int flags, float alpha, Matrix matrix,
Rect windowCrop, int layer, SurfaceControl relativeTo, int relativeLayer,
- float cornerRadius, int backgroundBlurRadius, boolean visible) {
+ float cornerRadius, int backgroundBlurRadius, boolean visible, float shadowRadius) {
this.flags = flags;
this.surface = surface;
this.alpha = alpha;
@@ -334,6 +329,7 @@ public class SyncRtSurfaceTransactionApplierCompat {
this.cornerRadius = cornerRadius;
this.backgroundBlurRadius = backgroundBlurRadius;
this.visible = visible;
+ this.shadowRadius = shadowRadius;
}
private final int flags;
@@ -349,6 +345,7 @@ public class SyncRtSurfaceTransactionApplierCompat {
public final SurfaceControl relativeTo;
public final int relativeLayer;
public final boolean visible;
+ public final float shadowRadius;
public void applyTo(SurfaceControl.Transaction t) {
if ((flags & FLAG_MATRIX) != 0) {
@@ -379,6 +376,9 @@ public class SyncRtSurfaceTransactionApplierCompat {
if ((flags & FLAG_RELATIVE_LAYER) != 0) {
t.setRelativeLayer(surface, relativeTo, relativeLayer);
}
+ if ((flags & FLAG_SHADOW_RADIUS) != 0) {
+ t.setShadowRadius(surface, shadowRadius);
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index d79c96ea4774..289ffbe518c0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -16,6 +16,7 @@
package com.android.systemui.biometrics;
+import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.SuppressLint;
@@ -25,6 +26,7 @@ import android.content.res.TypedArray;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.PowerManager;
import android.os.UserHandle;
@@ -41,6 +43,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.BrightnessSynchronizer;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeReceiver;
@@ -50,13 +53,22 @@ import com.android.systemui.util.settings.SystemSettings;
import java.io.FileWriter;
import java.io.IOException;
+import java.util.List;
import javax.inject.Inject;
/**
* Shows and hides the under-display fingerprint sensor (UDFPS) overlay, handles UDFPS touch events,
* and coordinates triggering of the high-brightness mode (HBM).
+ *
+ * Note that the current architecture is designed so that a single {@link UdfpsController}
+ * controls/manages all UDFPS sensors. In other words, a single controller is registered with
+ * {@link com.android.server.biometrics.sensors.fingerprint.FingerprintService}, and interfaces such
+ * as {@link FingerprintManager#onFingerDown(int, int, int, float, float)} or
+ * {@link IUdfpsOverlayController#showUdfpsOverlay(int)}should all have
+ * {@code sensorId} parameters.
*/
+@SuppressWarnings("deprecation")
class UdfpsController implements DozeReceiver {
private static final String TAG = "UdfpsController";
// Gamma approximation for the sRGB color space.
@@ -64,6 +76,10 @@ class UdfpsController implements DozeReceiver {
private static final long AOD_INTERRUPT_TIMEOUT_MILLIS = 1000;
private final FingerprintManager mFingerprintManager;
+ // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
+ // sensors, this, in addition to a lot of the code here, will be updated.
+ @VisibleForTesting
+ final int mUdfpsSensorId;
private final WindowManager mWindowManager;
private final SystemSettings mSystemSettings;
private final DelayableExecutor mFgExecutor;
@@ -103,17 +119,17 @@ class UdfpsController implements DozeReceiver {
public class UdfpsOverlayController extends IUdfpsOverlayController.Stub {
@Override
- public void showUdfpsOverlay() {
+ public void showUdfpsOverlay(int sensorId) {
UdfpsController.this.setShowOverlay(true);
}
@Override
- public void hideUdfpsOverlay() {
+ public void hideUdfpsOverlay(int sensorId) {
UdfpsController.this.setShowOverlay(false);
}
@Override
- public void setDebugMessage(String message) {
+ public void setDebugMessage(int sensorId, String message) {
mView.setDebugMessage(message);
}
}
@@ -165,6 +181,17 @@ class UdfpsController implements DozeReceiver {
mFgExecutor = fgExecutor;
mLayoutParams = createLayoutParams(context);
+ int udfpsSensorId = -1;
+ for (FingerprintSensorProperties props : mFingerprintManager.getSensorProperties()) {
+ if (props.isAnyUdfpsType()) {
+ udfpsSensorId = props.sensorId;
+ break;
+ }
+ }
+ // At least one UDFPS sensor exists
+ checkArgument(udfpsSensorId != -1);
+ mUdfpsSensorId = udfpsSensorId;
+
mView = (UdfpsView) inflater.inflate(R.layout.udfps_view, null, false);
mHbmPath = resources.getString(R.string.udfps_hbm_sysfs_path);
@@ -347,7 +374,7 @@ class UdfpsController implements DozeReceiver {
fw.write(mHbmEnableCommand);
fw.close();
}
- mFingerprintManager.onFingerDown(x, y, minor, major);
+ mFingerprintManager.onFingerDown(mUdfpsSensorId, x, y, minor, major);
} catch (IOException e) {
mView.hideScrimAndDot();
Log.e(TAG, "onFingerDown | failed to enable HBM: " + e.getMessage());
@@ -355,7 +382,7 @@ class UdfpsController implements DozeReceiver {
}
private void onFingerUp() {
- mFingerprintManager.onFingerUp();
+ mFingerprintManager.onFingerUp(mUdfpsSensorId);
// Hiding the scrim before disabling HBM results in less noticeable flicker.
mView.hideScrimAndDot();
if (mHbmSupported) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index e835ea206e59..46ef9bc0948e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -74,7 +74,7 @@ public class StackAnimationController extends
*/
public static final int DEFAULT_STIFFNESS = 12000;
public static final float IME_ANIMATION_STIFFNESS = SpringForce.STIFFNESS_LOW;
- private static final int FLING_FOLLOW_STIFFNESS = 20000;
+ private static final int FLING_FOLLOW_STIFFNESS = 500;
public static final float DEFAULT_BOUNCINESS = 0.9f;
private final PhysicsAnimator.SpringConfig mAnimateOutSpringConfig =
diff --git a/packages/SystemUI/src/com/android/systemui/emergency/EmergencyGesture.java b/packages/SystemUI/src/com/android/systemui/emergency/EmergencyGesture.java
new file mode 100644
index 000000000000..dccb24dfe21e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/emergency/EmergencyGesture.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.emergency;
+
+/**
+ * Constants for the Emergency gesture.
+ *
+ * TODO (b/169175022) Update classname and docs when feature name is locked
+ */
+public final class EmergencyGesture {
+
+ /**
+ * Launches the emergency flow.
+ *
+ * <p>The emergency flow is triggered by the Emergency gesture. By default the flow will call
+ * local emergency services, though OEMs can customize the flow.
+ *
+ * <p>This action can only be triggered by System UI through the emergency gesture.
+ *
+ * <p>TODO (b/169175022) Update action name and docs when feature name is locked
+ */
+ public static final String ACTION_LAUNCH_EMERGENCY =
+ "com.android.systemui.action.LAUNCH_EMERGENCY";
+
+ private EmergencyGesture() {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index daef2c506ad3..5f726cd1e1f9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -38,6 +38,7 @@ import android.provider.Settings;
import android.service.notification.ZenModeConfig;
import android.text.TextUtils;
import android.text.style.StyleSpan;
+import android.util.Log;
import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
@@ -52,6 +53,8 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SystemUIAppComponentFactory;
+import com.android.systemui.SystemUIFactory;
+import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.StatusBarState;
@@ -62,6 +65,8 @@ import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.wakelock.SettableWakeLock;
import com.android.systemui.util.wakelock.WakeLock;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
@@ -80,6 +85,8 @@ public class KeyguardSliceProvider extends SliceProvider implements
NotificationMediaManager.MediaListener, StatusBarStateController.StateListener,
SystemUIAppComponentFactory.ContextInitializer {
+ private static final String TAG = "KgdSliceProvider";
+
private static final StyleSpan BOLD_STYLE = new StyleSpan(Typeface.BOLD);
public static final String KEYGUARD_SLICE_URI = "content://com.android.systemui.keyguard/main";
private static final String KEYGUARD_HEADER_URI =
@@ -310,7 +317,25 @@ public class KeyguardSliceProvider extends SliceProvider implements
mDatePattern = getContext().getString(R.string.system_ui_aod_date_pattern);
mPendingIntent = PendingIntent.getActivity(getContext(), 0,
new Intent(getContext(), KeyguardSliceProvider.class), 0);
- mMediaManager.addCallback(this);
+ try {
+ //TODO(b/168778439): Remove this whole try catch. This is for debugging in dogfood.
+ mMediaManager.addCallback(this);
+ } catch (NullPointerException e) {
+ // We are sometimes failing to set the media manager. Why?
+ Log.w(TAG, "Failed to setup mMediaManager. Trying again.");
+ SysUIComponent rootComponent = SystemUIFactory.getInstance().getSysUIComponent();
+ try {
+ Method injectMethod = rootComponent.getClass()
+ .getMethod("inject", getClass());
+ injectMethod.invoke(rootComponent, this);
+ Log.w("TAG", "mMediaManager is now: " + mMediaManager);
+ } catch (NoSuchMethodException ex) {
+ Log.e(TAG, "Failed to find inject method for KeyguardSliceProvider", ex);
+ } catch (IllegalAccessException | InvocationTargetException ex) {
+ Log.e(TAG, "Failed to call inject", ex);
+ }
+ throw e;
+ }
mStatusBarStateController.addCallback(this);
mNextAlarmController.addCallback(this);
mZenModeController.addCallback(this);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index fb86535b4e90..b0fcdf82e2fe 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -325,9 +325,13 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize
return;
}
+ final Configuration initialConfig = mInitialState.remove(mToken.asBinder());
+ if (initialConfig == null) {
+ Log.wtf(TAG, "Token not in record, this should not happen mToken=" + mToken);
+ return;
+ }
mPipUiEventLoggerLogger.log(
PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN);
- final Configuration initialConfig = mInitialState.remove(mToken.asBinder());
final boolean orientationDiffers = initialConfig.windowConfiguration.getRotation()
!= mPipBoundsHandler.getDisplayRotation();
final WindowContainerTransaction wct = new WindowContainerTransaction();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 2e258d56ece0..8fec5a2acb8d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -30,6 +30,7 @@ import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Rect;
import android.media.AudioManager;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.provider.AlarmClock;
@@ -64,6 +65,8 @@ import com.android.systemui.BatteryMeterView;
import com.android.systemui.DualToneHandler;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.demomode.DemoMode;
+import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
@@ -151,6 +154,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements
private Space mSpace;
private BatteryMeterView mBatteryRemainingIcon;
private RingerModeTracker mRingerModeTracker;
+ private DemoModeController mDemoModeController;
+ private DemoMode mDemoModeReceiver;
private boolean mAllIndicatorsEnabled;
private boolean mMicCameraIndicatorsEnabled;
@@ -207,7 +212,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements
StatusBarIconController statusBarIconController,
ActivityStarter activityStarter, PrivacyItemController privacyItemController,
CommandQueue commandQueue, RingerModeTracker ringerModeTracker,
- UiEventLogger uiEventLogger) {
+ UiEventLogger uiEventLogger, DemoModeController demoModeController) {
super(context, attrs);
mAlarmController = nextAlarmController;
mZenController = zenModeController;
@@ -219,6 +224,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements
mCommandQueue = commandQueue;
mRingerModeTracker = ringerModeTracker;
mUiEventLogger = uiEventLogger;
+ mDemoModeController = demoModeController;
}
@Override
@@ -268,6 +274,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements
mClockView = findViewById(R.id.clock);
mClockView.setOnClickListener(this);
+ mDemoModeReceiver = new ClockDemoModeReceiver(mClockView);
mDateView = findViewById(R.id.date);
mSpace = findViewById(R.id.space);
@@ -526,6 +533,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements
updateStatusText();
});
mStatusBarIconController.addIconGroup(mIconManager);
+ mDemoModeController.addCallback(mDemoModeReceiver);
requestApplyInsets();
}
@@ -606,6 +614,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements
setListening(false);
mRingerModeTracker.getRingerModeInternal().removeObservers(this);
mStatusBarIconController.removeIconGroup(mIconManager);
+ mDemoModeController.removeCallback(mDemoModeReceiver);
super.onDetachedFromWindow();
}
@@ -769,4 +778,33 @@ public class QuickStatusBarHeader extends RelativeLayout implements
private boolean getChipEnabled() {
return mMicCameraIndicatorsEnabled || mAllIndicatorsEnabled;
}
+
+ private static class ClockDemoModeReceiver implements DemoMode {
+ private Clock mClockView;
+
+ @Override
+ public List<String> demoCommands() {
+ return List.of(COMMAND_CLOCK);
+ }
+
+ ClockDemoModeReceiver(Clock clockView) {
+ mClockView = clockView;
+ }
+
+ @Override
+ public void dispatchDemoCommand(String command, Bundle args) {
+ mClockView.dispatchDemoCommand(command, args);
+ }
+
+ @Override
+ public void onDemoModeStarted() {
+ mClockView.onDemoModeStarted();
+ }
+
+ @Override
+ public void onDemoModeFinished() {
+ mClockView.onDemoModeFinished();
+ }
+ }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
index 47002683c6b9..bbeff6ece902 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
@@ -16,30 +16,17 @@
package com.android.systemui.recents;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-
import android.annotation.Nullable;
-import android.app.ActivityManager;
import android.app.trust.TrustManager;
import android.content.Context;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
-import android.view.Display;
-import android.widget.Toast;
import com.android.systemui.Dependency;
-import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.shared.recents.IOverviewProxy;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.wm.shell.splitscreen.SplitScreen;
import java.util.Optional;
@@ -56,7 +43,6 @@ public class OverviewProxyRecentsImpl implements RecentsImplementation {
private final static String TAG = "OverviewProxyRecentsImpl";
@Nullable
private final Lazy<StatusBar> mStatusBarLazy;
- private final Optional<SplitScreen> mSplitScreenOptional;
private Context mContext;
private Handler mHandler;
@@ -65,10 +51,8 @@ public class OverviewProxyRecentsImpl implements RecentsImplementation {
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Inject
- public OverviewProxyRecentsImpl(Optional<Lazy<StatusBar>> statusBarLazy,
- Optional<SplitScreen> splitScreenOptional) {
+ public OverviewProxyRecentsImpl(Optional<Lazy<StatusBar>> statusBarLazy) {
mStatusBarLazy = statusBarLazy.orElse(null);
- mSplitScreenOptional = splitScreenOptional;
}
@Override
@@ -140,42 +124,4 @@ public class OverviewProxyRecentsImpl implements RecentsImplementation {
// Do nothing
}
}
-
- @Override
- public boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds,
- int metricsDockAction) {
- Point realSize = new Point();
- if (initialBounds == null) {
- mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY)
- .getRealSize(realSize);
- initialBounds = new Rect(0, 0, realSize.x, realSize.y);
- }
-
- ActivityManager.RunningTaskInfo runningTask =
- ActivityManagerWrapper.getInstance().getRunningTask();
- final int activityType = runningTask != null
- ? runningTask.configuration.windowConfiguration.getActivityType()
- : ACTIVITY_TYPE_UNDEFINED;
- boolean screenPinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive();
- boolean isRunningTaskInHomeOrRecentsStack =
- activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS;
- if (runningTask != null && !isRunningTaskInHomeOrRecentsStack && !screenPinningActive) {
- if (runningTask.supportsSplitScreenMultiWindow) {
- if (ActivityManagerWrapper.getInstance().setTaskWindowingModeSplitScreenPrimary(
- runningTask.id, stackCreateMode, initialBounds)) {
- mSplitScreenOptional.ifPresent(splitScreen -> {
- splitScreen.onDockedTopTask();
- // The overview service is handling split screen, so just skip the wait
- // for the first draw and notify the divider to start animating now
- splitScreen.onRecentsDrawn();
- });
- return true;
- }
- } else {
- Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text,
- Toast.LENGTH_SHORT).show();
- }
- }
- return false;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index df61fd19ad45..6f6dd9cb22c7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -19,7 +19,6 @@ package com.android.systemui.recents;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Configuration;
-import android.graphics.Rect;
import android.provider.Settings;
import com.android.systemui.SystemUI;
@@ -120,17 +119,6 @@ public class Recents extends SystemUI implements CommandQueue.Callbacks {
mImpl.cancelPreloadRecentApps();
}
- public boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds,
- int metricsDockAction) {
- // Ensure the device has been provisioned before allowing the user to interact with
- // recents
- if (!isUserSetup()) {
- return false;
- }
-
- return mImpl.splitPrimaryTask(stackCreateMode, initialBounds, metricsDockAction);
- }
-
/**
* @return whether this device is provisioned and the current user is set up.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
index a641730ac64e..8848dbbda5e7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
@@ -17,7 +17,6 @@ package com.android.systemui.recents;
import android.content.Context;
import android.content.res.Configuration;
-import android.graphics.Rect;
import java.io.PrintWriter;
@@ -35,10 +34,6 @@ public interface RecentsImplementation {
default void showRecentApps(boolean triggeredFromAltTab) {}
default void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {}
default void toggleRecentApps() {}
- default boolean splitPrimaryTask(int stackCreateMode, Rect initialBounds,
- int metricsDockAction) {
- return false;
- }
default void dump(PrintWriter pw) {}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
index b9b4f42a66e1..6202057b9ef1 100644
--- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
@@ -16,9 +16,6 @@
package com.android.systemui.shortcut;
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
-
import android.content.Context;
import android.content.res.Configuration;
import android.os.RemoteException;
@@ -29,7 +26,6 @@ import android.view.WindowManagerGlobal;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.recents.Recents;
import com.android.wm.shell.splitscreen.DividerView;
import com.android.wm.shell.splitscreen.SplitScreen;
@@ -46,7 +42,6 @@ public class ShortcutKeyDispatcher extends SystemUI
private static final String TAG = "ShortcutKeyDispatcher";
private final Optional<SplitScreen> mSplitScreenOptional;
- private final Recents mRecents;
private ShortcutKeyServiceProxy mShortcutKeyServiceProxy = new ShortcutKeyServiceProxy(this);
private IWindowManager mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
@@ -60,11 +55,9 @@ public class ShortcutKeyDispatcher extends SystemUI
protected final long SC_DOCK_RIGHT = META_MASK | KeyEvent.KEYCODE_RIGHT_BRACKET;
@Inject
- public ShortcutKeyDispatcher(Context context,
- Optional<SplitScreen> splitScreenOptional, Recents recents) {
+ public ShortcutKeyDispatcher(Context context, Optional<SplitScreen> splitScreenOptional) {
super(context);
mSplitScreenOptional = splitScreenOptional;
- mRecents = recents;
}
/**
@@ -96,8 +89,7 @@ public class ShortcutKeyDispatcher extends SystemUI
}
private void handleDockKey(long shortcutCode) {
- if (mSplitScreenOptional.isPresent()) {
- SplitScreen splitScreen = mSplitScreenOptional.get();
+ mSplitScreenOptional.ifPresent(splitScreen -> {
if (splitScreen.isDividerVisible()) {
// If there is already a docked window, we respond by resizing the docking pane.
DividerView dividerView = splitScreen.getDividerView();
@@ -112,12 +104,9 @@ public class ShortcutKeyDispatcher extends SystemUI
dividerView.stopDragging(target.position, 0f, false /* avoidDismissStart */,
true /* logMetrics */);
return;
+ } else {
+ splitScreen.splitPrimaryTask();
}
- }
-
- // Split the screen
- mRecents.splitPrimaryTask((shortcutCode == SC_DOCK_LEFT)
- ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
- : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, null, -1);
+ });
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 3d51854a348c..54fb863b5de7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -168,7 +168,7 @@ public class LockIcon extends KeyguardAffordanceView {
int iconRes = isAnim ? getThemedAnimationResId(lockAnimIndex) : getIconForState(newState);
if (!mDrawableCache.contains(iconRes)) {
- mDrawableCache.put(iconRes, getResources().getDrawable(iconRes));
+ mDrawableCache.put(iconRes, getContext().getDrawable(iconRes));
}
return mDrawableCache.get(iconRes);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 994af090d21f..e7c29b6b54b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.phone;
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.WindowType;
@@ -37,7 +35,6 @@ import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASL
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_INVALID;
-import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_LEFT;
import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
@@ -174,7 +171,6 @@ import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.Snoo
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanel;
-import com.android.systemui.recents.Recents;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.shared.system.WindowManagerWrapper;
@@ -718,7 +714,6 @@ public class StatusBar extends SystemUI implements DemoMode,
DozeScrimController dozeScrimController,
VolumeComponent volumeComponent,
CommandQueue commandQueue,
- Optional<Recents> recentsOptional,
Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
PluginManager pluginManager,
Optional<SplitScreen> splitScreenOptional,
@@ -799,7 +794,6 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationShadeDepthControllerLazy = notificationShadeDepthControllerLazy;
mVolumeComponent = volumeComponent;
mCommandQueue = commandQueue;
- mRecentsOptional = recentsOptional;
mStatusBarComponentBuilder = statusBarComponentBuilder;
mPluginManager = pluginManager;
mSplitScreenOptional = splitScreenOptional;
@@ -1548,35 +1542,37 @@ public class StatusBar extends SystemUI implements DemoMode,
}
public boolean toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) {
- if (!mRecentsOptional.isPresent()) {
+ if (!mSplitScreenOptional.isPresent()) {
return false;
}
- if (mSplitScreenOptional.isPresent()) {
- SplitScreen splitScreen = mSplitScreenOptional.get();
- if (splitScreen.isDividerVisible()) {
- if (splitScreen.isMinimized()
- && !splitScreen.isHomeStackResizable()) {
- // Undocking from the minimized state is not supported
- return false;
- } else {
- splitScreen.onUndockingTask();
- if (metricsUndockAction != -1) {
- mMetricsLogger.action(metricsUndockAction);
- }
- }
- return true;
+ final SplitScreen splitScreen = mSplitScreenOptional.get();
+ if (splitScreen.isDividerVisible()) {
+ if (splitScreen.isMinimized() && !splitScreen.isHomeStackResizable()) {
+ // Undocking from the minimized state is not supported
+ return false;
}
+
+ splitScreen.onUndockingTask();
+ if (metricsUndockAction != -1) {
+ mMetricsLogger.action(metricsUndockAction);
+ }
+ return true;
}
final int navbarPos = WindowManagerWrapper.getInstance().getNavBarPosition(mDisplayId);
if (navbarPos == NAV_BAR_POS_INVALID) {
return false;
}
- int createMode = navbarPos == NAV_BAR_POS_LEFT
- ? SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT
- : SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
- return mRecentsOptional.get().splitPrimaryTask(createMode, null, metricsDockAction);
+
+ if (splitScreen.splitPrimaryTask()) {
+ if (metricsDockAction != -1) {
+ mMetricsLogger.action(metricsDockAction);
+ }
+ return true;
+ }
+
+ return false;
}
/**
@@ -4121,8 +4117,6 @@ public class StatusBar extends SystemUI implements DemoMode,
protected Display mDisplay;
private int mDisplayId;
- private final Optional<Recents> mRecentsOptional;
-
protected NotificationShelfController mNotificationShelfController;
private final Lazy<AssistManager> mAssistManagerLazy;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 3f29a4ea5b00..6d4099b656cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -43,7 +43,6 @@ import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.PluginDependencyProvider;
-import com.android.systemui.recents.Recents;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
@@ -175,7 +174,6 @@ public interface StatusBarPhoneModule {
DozeScrimController dozeScrimController,
VolumeComponent volumeComponent,
CommandQueue commandQueue,
- Optional<Recents> recentsOptional,
Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
PluginManager pluginManager,
Optional<SplitScreen> splitScreenOptional,
@@ -254,7 +252,6 @@ public interface StatusBarPhoneModule {
dozeScrimController,
volumeComponent,
commandQueue,
- recentsOptional,
statusBarComponentBuilder,
pluginManager,
splitScreenOptional,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvNotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvNotificationPanel.java
index 7a78c157e5b4..0bd36240a366 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvNotificationPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvNotificationPanel.java
@@ -58,6 +58,10 @@ public class TvNotificationPanel extends SystemUI implements CommandQueue.Callba
if (!mNotificationHandlerPackage.isEmpty()) {
startNotificationHandlerActivity(
new Intent(NotificationManager.ACTION_TOGGLE_NOTIFICATION_HANDLER_PANEL));
+ } else {
+ Log.w(TAG,
+ "Not toggling notification panel: config_notificationHandlerPackage is "
+ + "empty");
}
}
@@ -66,6 +70,10 @@ public class TvNotificationPanel extends SystemUI implements CommandQueue.Callba
if (!mNotificationHandlerPackage.isEmpty()) {
startNotificationHandlerActivity(
new Intent(NotificationManager.ACTION_OPEN_NOTIFICATION_HANDLER_PANEL));
+ } else {
+ Log.w(TAG,
+ "Not expanding notification panel: config_notificationHandlerPackage is "
+ + "empty");
}
}
@@ -77,6 +85,9 @@ public class TvNotificationPanel extends SystemUI implements CommandQueue.Callba
NotificationManager.ACTION_CLOSE_NOTIFICATION_HANDLER_PANEL);
closeNotificationIntent.setPackage(mNotificationHandlerPackage);
mContext.sendBroadcastAsUser(closeNotificationIntent, UserHandle.CURRENT);
+ } else {
+ Log.w(TAG,
+ "Not closing notification panel: config_notificationHandlerPackage is empty");
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
index a50de45e547b..1e6a9e8dc007 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
@@ -32,6 +32,8 @@ import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreenController;
+import java.util.concurrent.Executor;
+
import dagger.Module;
import dagger.Provides;
@@ -45,9 +47,10 @@ public class TvWMShellModule {
@SysUISingleton
@Provides
static DisplayImeController provideDisplayImeController(IWindowManager wmService,
- DisplayController displayController, @Main Handler mainHandler,
+ DisplayController displayController, @Main Executor mainExecutor,
TransactionPool transactionPool) {
- return new DisplayImeController(wmService, displayController, mainHandler, transactionPool);
+ return new DisplayImeController(wmService, displayController, mainExecutor,
+ transactionPool);
}
static SplitScreen provideSplitScreen(Context context,
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 3142c1e762e9..b4852b28619c 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -45,6 +45,7 @@ import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.util.Optional;
+import java.util.concurrent.Executor;
import dagger.Module;
import dagger.Provides;
@@ -59,9 +60,10 @@ public class WMShellModule {
@SysUISingleton
@Provides
static DisplayImeController provideDisplayImeController(IWindowManager wmService,
- DisplayController displayController, @Main Handler mainHandler,
+ DisplayController displayController, @Main Executor mainExecutor,
TransactionPool transactionPool) {
- return new DisplayImeController(wmService, displayController, mainHandler, transactionPool);
+ return new DisplayImeController(wmService, displayController, mainExecutor,
+ transactionPool);
}
@SysUISingleton
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 9b9f840e5383..7df9f1fff844 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.biometrics;
+import static junit.framework.Assert.assertEquals;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.eq;
@@ -25,7 +27,9 @@ import static org.mockito.Mockito.when;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.hardware.biometrics.SensorProperties;
import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -54,11 +58,18 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
+import java.util.ArrayList;
+import java.util.List;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
public class UdfpsControllerTest extends SysuiTestCase {
+ // Use this for inputs going into SystemUI. Use UdfpsController.mUdfpsSensorId for things
+ // leaving SystemUI.
+ private static final int TEST_UDFPS_SENSOR_ID = 1;
+
@Rule
public MockitoRule rule = MockitoJUnit.rule();
@@ -98,6 +109,13 @@ public class UdfpsControllerTest extends SysuiTestCase {
public void setUp() {
setUpResources();
when(mLayoutInflater.inflate(R.layout.udfps_view, null, false)).thenReturn(mUdfpsView);
+ final List<FingerprintSensorProperties> props = new ArrayList<>();
+ props.add(new FingerprintSensorProperties(TEST_UDFPS_SENSOR_ID,
+ SensorProperties.STRENGTH_STRONG,
+ 5 /* maxEnrollmentsPerUser */,
+ FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
+ true /* resetLockoutRequiresHardwareAuthToken */));
+ when(mFingerprintManager.getSensorProperties()).thenReturn(props);
mSystemSettings = new FakeSettings();
mFgExecutor = new FakeExecutor(new FakeSystemClock());
mUdfpsController = new UdfpsController(
@@ -112,6 +130,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
mFgExecutor);
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
mOverlayController = mOverlayCaptor.getValue();
+
+ assertEquals(TEST_UDFPS_SENSOR_ID, mUdfpsController.mUdfpsSensorId);
}
private void setUpResources() {
@@ -138,15 +158,15 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void showUdfpsOverlay_addsViewToWindow() throws RemoteException {
- mOverlayController.showUdfpsOverlay();
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
mFgExecutor.runAllReady();
verify(mWindowManager).addView(eq(mUdfpsView), any());
}
@Test
public void hideUdfpsOverlay_removesViewFromWindow() throws RemoteException {
- mOverlayController.showUdfpsOverlay();
- mOverlayController.hideUdfpsOverlay();
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
+ mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
mFgExecutor.runAllReady();
verify(mWindowManager).removeView(eq(mUdfpsView));
}
@@ -156,7 +176,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN that the bouncer is showing
mUdfpsController.setBouncerVisibility(/* isShowing */ true);
// WHEN a request to show the overlay is received
- mOverlayController.showUdfpsOverlay();
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
mFgExecutor.runAllReady();
// THEN the overlay is not attached
verify(mWindowManager, never()).addView(eq(mUdfpsView), any());
@@ -165,7 +185,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void setBouncerVisibility_overlayDetached() throws RemoteException {
// GIVEN that the overlay has been requested
- mOverlayController.showUdfpsOverlay();
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
// WHEN the bouncer becomes visible
mUdfpsController.setBouncerVisibility(/* isShowing */ true);
mFgExecutor.runAllReady();
@@ -178,7 +198,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
// GIVEN that the bouncer is visible
mUdfpsController.setBouncerVisibility(/* isShowing */ true);
// AND the overlay has been requested
- mOverlayController.showUdfpsOverlay();
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
// WHEN the bouncer is closed
mUdfpsController.setBouncerVisibility(/* isShowing */ false);
mFgExecutor.runAllReady();
@@ -193,7 +213,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
when(mUdfpsView.isValidTouch(anyFloat(), anyFloat(), anyFloat())).thenReturn(true);
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay();
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
mFgExecutor.runAllReady();
// WHEN ACTION_DOWN is received
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
@@ -201,7 +221,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
event.recycle();
// THEN the event is passed to the FingerprintManager
- verify(mFingerprintManager).onFingerDown(eq(0), eq(0), eq(0f), eq(0f));
+ verify(mFingerprintManager).onFingerDown(eq(mUdfpsController.mUdfpsSensorId), eq(0), eq(0),
+ eq(0f), eq(0f));
// AND the scrim and dot is shown
verify(mUdfpsView).showScrimAndDot();
}
@@ -209,12 +230,13 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void aodInterrupt() throws RemoteException {
// GIVEN that the overlay is showing
- mOverlayController.showUdfpsOverlay();
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
mFgExecutor.runAllReady();
// WHEN fingerprint is requested because of AOD interrupt
mUdfpsController.onAodInterrupt(0, 0);
// THEN the event is passed to the FingerprintManager
- verify(mFingerprintManager).onFingerDown(eq(0), eq(0), anyFloat(), anyFloat());
+ verify(mFingerprintManager).onFingerDown(eq(mUdfpsController.mUdfpsSensorId), eq(0), eq(0),
+ anyFloat(), anyFloat());
// AND the scrim and dot is shown
verify(mUdfpsView).showScrimAndDot();
}
@@ -222,7 +244,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void cancelAodInterrupt() throws RemoteException {
// GIVEN AOD interrupt
- mOverlayController.showUdfpsOverlay();
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
mFgExecutor.runAllReady();
mUdfpsController.onAodInterrupt(0, 0);
// WHEN it is cancelled
@@ -234,7 +256,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void aodInterruptTimeout() throws RemoteException {
// GIVEN AOD interrupt
- mOverlayController.showUdfpsOverlay();
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
mFgExecutor.runAllReady();
mUdfpsController.onAodInterrupt(0, 0);
// WHEN it times out
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 23b12d4e115f..a6ea9966a0f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -93,7 +93,6 @@ import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.PluginDependencyProvider;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.recents.Recents;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
@@ -232,7 +231,6 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private KeyguardLiftController mKeyguardLiftController;
@Mock private VolumeComponent mVolumeComponent;
@Mock private CommandQueue mCommandQueue;
- @Mock private Recents mRecents;
@Mock private Provider<StatusBarComponent.Builder> mStatusBarComponentBuilderProvider;
@Mock private StatusBarComponent.Builder mStatusBarComponentBuilder;
@Mock private StatusBarComponent mStatusBarComponent;
@@ -392,7 +390,6 @@ public class StatusBarTest extends SysuiTestCase {
mDozeScrimController,
mVolumeComponent,
mCommandQueue,
- Optional.of(mRecents),
mStatusBarComponentBuilderProvider,
mPluginManager,
Optional.of(mSplitScreen),
diff --git a/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java b/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java
index 73fc833fabf5..084743db03c4 100644
--- a/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java
+++ b/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java
@@ -25,7 +25,6 @@ import static android.system.OsConstants.SOCK_NONBLOCK;
import static android.system.OsConstants.SOCK_RAW;
import android.net.util.InterfaceParams;
-import android.net.util.PacketReader;
import android.net.util.SocketUtils;
import android.net.util.TetheringUtils;
import android.os.Handler;
@@ -33,6 +32,8 @@ import android.system.ErrnoException;
import android.system.Os;
import android.util.Log;
+import com.android.net.module.util.PacketReader;
+
import java.io.FileDescriptor;
import java.io.IOException;
import java.net.Inet6Address;
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 7dd5290ee83b..64d5025807e7 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -2104,7 +2104,7 @@ public class Tethering {
}
private boolean hasCallingPermission(@NonNull String permission) {
- return mContext.checkCallingPermission(permission) == PERMISSION_GRANTED;
+ return mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED;
}
/** Unregister tethering event callback */
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 8a1baf25481b..da5d1c2aa61e 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -136,8 +136,6 @@ import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
import android.net.netlink.InetDiagMessage;
import android.net.shared.PrivateDnsConfig;
-import android.net.util.LinkPropertiesUtils.CompareOrUpdateResult;
-import android.net.util.LinkPropertiesUtils.CompareResult;
import android.net.util.MultinetworkPolicyTracker;
import android.net.util.NetdService;
import android.os.Binder;
@@ -195,6 +193,8 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.LocationPermissionChecker;
import com.android.internal.util.MessageUtils;
import com.android.internal.util.XmlUtils;
+import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult;
+import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
import com.android.server.am.BatteryStatsService;
import com.android.server.connectivity.AutodestructReference;
import com.android.server.connectivity.DataConnectionStats;
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index 4a1820a8e538..d90750548114 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -25,7 +25,6 @@ import android.net.Uri;
import android.net.nsd.INsdManager;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
-import android.net.util.nsd.DnsSdTxtRecord;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
@@ -42,6 +41,7 @@ import com.android.internal.util.AsyncChannel;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
+import com.android.net.module.util.DnsSdTxtRecord;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4f056df4dff9..ffdcd156122e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17334,4 +17334,18 @@ public class ActivityManagerService extends IActivityManager.Stub
throw new SecurityException("Caller uid " + callerUid + " cannot set freezer state ");
}
}
+
+ /**
+ * Holds the AM lock for the specified amount of milliseconds.
+ * Intended for use by the tests that need to imitate lock contention.
+ * Requires permission identity of the shell UID.
+ */
+ @Override
+ public void holdLock(int durationMs) {
+ enforceCallingPermission(Manifest.permission.INJECT_EVENTS, "holdLock");
+
+ synchronized (this) {
+ SystemClock.sleep(durationMs);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 1bf62a0c7b7e..58ac2dc869ce 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -733,10 +733,6 @@ public final class OomAdjuster {
uidRec.reset();
}
- if (mService.mAtmInternal != null) {
- mService.mAtmInternal.rankTaskLayersIfNeeded();
- }
-
mAdjSeq++;
if (fullUpdate) {
mNewNumServiceProcs = 0;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 2dced8d704bb..ebc5b59363df 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1909,8 +1909,8 @@ class ProcessRecord implements WindowProcessListener {
}
callback.initialize(this, adj, foregroundActivities, procState, schedGroup, appUid, logUid,
processCurTop);
- final int minLayer = getWindowProcessController().computeOomAdjFromActivities(
- ProcessList.VISIBLE_APP_LAYER_MAX, callback);
+ final int minLayer = Math.min(ProcessList.VISIBLE_APP_LAYER_MAX,
+ getWindowProcessController().computeOomAdjFromActivities(callback));
mCachedAdj = callback.adj;
mCachedForegroundActivities = callback.foregroundActivities;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 2903b9970033..cc9407913be9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -46,6 +46,7 @@ import android.os.Process;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.EventLog;
+import android.util.Pair;
import android.util.Slog;
import android.view.Surface;
@@ -79,7 +80,7 @@ public class FingerprintService extends SystemService {
private final LockoutResetDispatcher mLockoutResetDispatcher;
private final GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
private final LockPatternUtils mLockPatternUtils;
- private Fingerprint21 mFingerprint21;
+ @NonNull private List<ServiceProvider> mServiceProviders;
/**
* Receives the incoming binder calls from FingerprintManager.
@@ -88,11 +89,8 @@ public class FingerprintService extends SystemService {
@Override // Binder call
public List<FingerprintSensorProperties> getSensorProperties(String opPackageName) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- final List<FingerprintSensorProperties> properties = new ArrayList<>();
-
- if (mFingerprint21 != null) {
- properties.add(mFingerprint21.getFingerprintSensorProperties());
- }
+ final List<FingerprintSensorProperties> properties =
+ FingerprintService.this.getSensorProperties();
Slog.d(TAG, "Retrieved sensor properties for: " + opPackageName
+ ", sensors: " + properties.size());
@@ -104,18 +102,26 @@ public class FingerprintService extends SystemService {
IFingerprintServiceReceiver receiver, String opPackageName) {
Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
- if (sensorId == mFingerprint21.getFingerprintSensorProperties().sensorId) {
- mFingerprint21.scheduleGenerateChallenge(token, receiver, opPackageName);
+ final ServiceProvider provider = getProviderForSensor(sensorId);
+ if (provider == null) {
+ Slog.w(TAG, "No matching sensor for generateChallenge, sensorId: " + sensorId);
return;
}
- Slog.w(TAG, "No matching sensor for generateChallenge, sensorId: " + sensorId);
+ provider.scheduleGenerateChallenge(sensorId, token, receiver, opPackageName);
}
@Override // Binder call
- public void revokeChallenge(IBinder token, String owner) {
+ public void revokeChallenge(IBinder token, String opPackageName) {
Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
- mFingerprint21.scheduleRevokeChallenge(token, owner);
+
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for revokeChallenge");
+ return;
+ }
+
+ provider.second.scheduleRevokeChallenge(provider.first, token, opPackageName);
}
@Override // Binder call
@@ -123,14 +129,28 @@ public class FingerprintService extends SystemService {
final IFingerprintServiceReceiver receiver, final String opPackageName,
Surface surface) {
Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
- mFingerprint21.scheduleEnroll(token, hardwareAuthToken, userId, receiver, opPackageName,
- surface);
+
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for enroll");
+ return;
+ }
+
+ provider.second.scheduleEnroll(provider.first, token, hardwareAuthToken, userId,
+ receiver, opPackageName, surface);
}
@Override // Binder call
public void cancelEnrollment(final IBinder token) {
Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
- mFingerprint21.cancelEnrollment(token);
+
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for cancelEnrollment");
+ return;
+ }
+
+ provider.second.cancelEnrollment(provider.first, token);
}
@Override // Binder call
@@ -169,8 +189,15 @@ public class FingerprintService extends SystemService {
!= PackageManager.PERMISSION_GRANTED;
final int statsClient = isKeyguard ? BiometricsProtoEnums.CLIENT_KEYGUARD
: BiometricsProtoEnums.CLIENT_FINGERPRINT_MANAGER;
- mFingerprint21.scheduleAuthenticate(token, operationId, userId, 0 /* cookie */,
- new ClientMonitorCallbackConverter(receiver), opPackageName,
+
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for authenticate");
+ return;
+ }
+
+ provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
+ 0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName,
restricted, statsClient, isKeyguard);
}
@@ -191,7 +218,13 @@ public class FingerprintService extends SystemService {
return;
}
- mFingerprint21.scheduleFingerDetect(token, userId,
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for detectFingerprint");
+ return;
+ }
+
+ provider.second.scheduleFingerDetect(provider.first, token, userId,
new ClientMonitorCallbackConverter(receiver), opPackageName, surface,
BiometricsProtoEnums.CLIENT_KEYGUARD);
}
@@ -203,8 +236,14 @@ public class FingerprintService extends SystemService {
Surface surface) {
Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for prepareForAuthentication");
+ return;
+ }
+
final boolean restricted = true; // BiometricPrompt is always restricted
- mFingerprint21.scheduleAuthenticate(token, operationId, userId, cookie,
+ provider.second.scheduleAuthenticate(provider.first, token, operationId, userId, cookie,
new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted,
BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, false /* isKeyguard */);
}
@@ -212,7 +251,14 @@ public class FingerprintService extends SystemService {
@Override // Binder call
public void startPreparedClient(int cookie) {
Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
- mFingerprint21.startPreparedClient(cookie);
+
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for startPreparedClient");
+ return;
+ }
+
+ provider.second.startPreparedClient(provider.first, cookie);
}
@@ -228,7 +274,13 @@ public class FingerprintService extends SystemService {
return;
}
- mFingerprint21.cancelAuthentication(token);
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for cancelAuthentication");
+ return;
+ }
+
+ provider.second.cancelAuthentication(provider.first, token);
}
@Override // Binder call
@@ -242,21 +294,41 @@ public class FingerprintService extends SystemService {
// For IBiometricsFingerprint2.1, cancelling fingerprint detect is the same as
// cancelling authentication.
- mFingerprint21.cancelAuthentication(token);
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for cancelFingerprintDetect");
+ return;
+ }
+
+ provider.second.cancelAuthentication(provider.first, token);
}
@Override // Binder call
public void cancelAuthenticationFromService(final IBinder token, final String opPackageName,
int callingUid, int callingPid, int callingUserId) {
Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
- mFingerprint21.cancelAuthentication(token);
+
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for cancelAuthenticationFromService");
+ return;
+ }
+
+ provider.second.cancelAuthentication(provider.first, token);
}
@Override // Binder call
public void remove(final IBinder token, final int fingerId, final int userId,
final IFingerprintServiceReceiver receiver, final String opPackageName) {
Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
- mFingerprint21.scheduleRemove(token, receiver, fingerId, userId, opPackageName);
+
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for remove");
+ return;
+ }
+ provider.second.scheduleRemove(provider.first, token, receiver, fingerId, userId,
+ opPackageName);
}
@Override
@@ -274,10 +346,14 @@ public class FingerprintService extends SystemService {
final long ident = Binder.clearCallingIdentity();
try {
- if (args.length > 0 && "--proto".equals(args[0])) {
- mFingerprint21.dumpProto(fd);
- } else {
- mFingerprint21.dumpInternal(pw);
+ for (ServiceProvider provider : mServiceProviders) {
+ for (FingerprintSensorProperties props : provider.getSensorProperties()) {
+ if (args.length > 0 && "--proto".equals(args[0])) {
+ provider.dumpProto(props.sensorId, fd);
+ } else {
+ provider.dumpInternal(props.sensorId, pw);
+ }
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -294,11 +370,12 @@ public class FingerprintService extends SystemService {
final long token = Binder.clearCallingIdentity();
try {
- if (mFingerprint21 == null) {
- Slog.e(TAG, "No HAL, caller: " + opPackageName);
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for isHardwareDetected, caller: " + opPackageName);
return false;
}
- return mFingerprint21.isHardwareDetected();
+ return provider.second.isHardwareDetected(provider.first);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -311,7 +388,13 @@ public class FingerprintService extends SystemService {
return;
}
- mFingerprint21.rename(fingerId, userId, name);
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for rename");
+ return;
+ }
+
+ provider.second.rename(provider.first, fingerId, userId, name);
}
@Override // Binder call
@@ -325,7 +408,8 @@ public class FingerprintService extends SystemService {
if (userId != UserHandle.getCallingUserId()) {
Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS);
}
- return mFingerprint21.getEnrolledFingerprints(userId);
+
+ return FingerprintService.this.getEnrolledFingerprints(userId, opPackageName);
}
@Override // Binder call
@@ -339,19 +423,32 @@ public class FingerprintService extends SystemService {
if (userId != UserHandle.getCallingUserId()) {
Utils.checkPermission(getContext(), INTERACT_ACROSS_USERS);
}
- return mFingerprint21.getEnrolledFingerprints(userId).size() > 0;
+ return !FingerprintService.this.getEnrolledFingerprints(userId, opPackageName)
+ .isEmpty();
}
@Override // Binder call
public @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- return mFingerprint21.getLockoutModeForUser(userId);
+
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for getLockoutModeForUser");
+ return LockoutTracker.LOCKOUT_NONE;
+ }
+ return provider.second.getLockoutModeForUser(provider.first, userId);
}
@Override // Binder call
public long getAuthenticatorId(int userId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- return mFingerprint21.getAuthenticatorId(userId);
+
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for getAuthenticatorId");
+ return 0;
+ }
+ return provider.second.getAuthenticatorId(provider.first, userId);
}
@Override // Binder call
@@ -359,12 +456,13 @@ public class FingerprintService extends SystemService {
@Nullable byte [] hardwareAuthToken, String opPackageName) {
Utils.checkPermission(getContext(), RESET_FINGERPRINT_LOCKOUT);
- if (sensorId == mFingerprint21.getFingerprintSensorProperties().sensorId) {
- mFingerprint21.scheduleResetLockout(userId);
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for resetLockout, caller: " + opPackageName);
return;
}
- Slog.w(TAG, "No matching sensor for resetLockout, sensorId: " + sensorId);
+ provider.second.scheduleResetLockout(sensorId, userId, hardwareAuthToken);
}
@Override
@@ -389,35 +487,52 @@ public class FingerprintService extends SystemService {
public void initializeConfiguration(int sensorId, int strength) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ final Fingerprint21 fingerprint21;
if ((Build.IS_USERDEBUG || Build.IS_ENG)
&& getContext().getResources().getBoolean(R.bool.allow_test_udfps)
&& Settings.Secure.getIntForUser(getContext().getContentResolver(),
Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */,
UserHandle.USER_CURRENT) != 0) {
- mFingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(), sensorId,
+ fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(), sensorId,
strength, mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
} else {
- mFingerprint21 = Fingerprint21.newInstance(getContext(), sensorId, strength,
+ fingerprint21 = Fingerprint21.newInstance(getContext(), sensorId, strength,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
}
+ mServiceProviders.add(fingerprint21);
}
@Override
- public void onFingerDown(int x, int y, float minor, float major) {
+ public void onFingerDown(int sensorId, int x, int y, float minor, float major) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- mFingerprint21.onFingerDown(x, y, minor, major);
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
+ if (provider == null) {
+ Slog.w(TAG, "No matching provider for onFingerDown, sensorId: " + sensorId);
+ return;
+ }
+ provider.onFingerDown(sensorId, x, y, minor, major);
}
@Override
- public void onFingerUp() {
+ public void onFingerUp(int sensorId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- mFingerprint21.onFingerUp();
+
+ final ServiceProvider provider = getProviderForSensor(sensorId);
+ if (provider == null) {
+ Slog.w(TAG, "No matching provider for onFingerUp, sensorId: " + sensorId);
+ return;
+ }
+ provider.onFingerUp(sensorId);
}
@Override
- public void setUdfpsOverlayController(IUdfpsOverlayController controller) {
+ public void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- mFingerprint21.setUdfpsOverlayController(controller);
+
+ for (ServiceProvider provider : mServiceProviders) {
+ provider.setUdfpsOverlayController(controller);
+ }
}
}
@@ -427,6 +542,7 @@ public class FingerprintService extends SystemService {
mGestureAvailabilityDispatcher = new GestureAvailabilityDispatcher();
mLockoutResetDispatcher = new LockoutResetDispatcher(context);
mLockPatternUtils = new LockPatternUtils(context);
+ mServiceProviders = new ArrayList<>();
}
@Override
@@ -434,6 +550,61 @@ public class FingerprintService extends SystemService {
publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
}
+ @Nullable
+ private ServiceProvider getProviderForSensor(int sensorId) {
+ for (ServiceProvider provider : mServiceProviders) {
+ if (provider.containsSensor(sensorId)) {
+ return provider;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * For devices with only a single provider, returns that provider. If no providers, or multiple
+ * providers exist, returns null.
+ */
+ @Nullable
+ private Pair<Integer, ServiceProvider> getSingleProvider() {
+ final List<FingerprintSensorProperties> properties = getSensorProperties();
+ if (properties.size() != 1) {
+ return null;
+ }
+
+ // Theoretically we can just return the first provider, but maybe this is easier to
+ // understand.
+ final int sensorId = properties.get(0).sensorId;
+ for (ServiceProvider provider : mServiceProviders) {
+ if (provider.containsSensor(sensorId)) {
+ return new Pair<>(sensorId, provider);
+ }
+ }
+
+ Slog.e(TAG, "Single sensor, but provider not found");
+ return null;
+ }
+
+ @NonNull
+ private List<FingerprintSensorProperties> getSensorProperties() {
+ final List<FingerprintSensorProperties> properties = new ArrayList<>();
+
+ for (ServiceProvider provider : mServiceProviders) {
+ properties.addAll(provider.getSensorProperties());
+ }
+ return properties;
+ }
+
+ @NonNull
+ private List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) {
+ final Pair<Integer, ServiceProvider> provider = getSingleProvider();
+ if (provider == null) {
+ Slog.w(TAG, "Null provider for getEnrolledFingerprints, caller: " + opPackageName);
+ return Collections.emptyList();
+ }
+
+ return provider.second.getEnrolledFingerprints(provider.first, userId);
+ }
+
/**
* Checks for public API invocations to ensure that permissions, etc are granted/correct.
*/
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
new file mode 100644
index 000000000000..1fcc58cd5833
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors.fingerprint;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import android.hardware.fingerprint.IUdfpsOverlayController;
+import android.os.IBinder;
+import android.view.Surface;
+
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.LockoutTracker;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Superset of features/functionalities that HALs provide to the rest of the framework. This is
+ * more or less mapped to the public and private APIs that {@link FingerprintManager} provide, and
+ * is used at the system server layer to provide easy mapping between request and provider.
+ *
+ * Note that providers support both single-sensor and multi-sensor HALs. In either case,
+ * {@link FingerprintService} must ensure that providers are only requested to perform operations
+ * on sensors that they own.
+ *
+ * For methods other than {@link #containsSensor(int)}, the caller must ensure that the sensorId
+ * passed in is supported by the provider. For example,
+ * if (serviceProvider.containsSensor(sensorId)) {
+ * serviceProvider.operation(sensorId, ...);
+ * }
+ *
+ * For operations that are supported by some providers but not others, clients are required
+ * to check (e.g. via {@link FingerprintManager#getSensorProperties()}) to ensure that the code
+ * path isn't taken. ServiceProviders will provide a no-op for unsupported operations to
+ * fail safely.
+ */
+@SuppressWarnings("deprecation")
+public interface ServiceProvider {
+ /**
+ * Checks if the specified sensor is owned by this provider.
+ */
+ boolean containsSensor(int sensorId);
+
+ @NonNull List<FingerprintSensorProperties> getSensorProperties();
+
+ void scheduleResetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken);
+
+ void scheduleGenerateChallenge(int sensorId, @NonNull IBinder token,
+ @NonNull IFingerprintServiceReceiver receiver, String opPackageName);
+
+ void scheduleRevokeChallenge(int sensorId, @NonNull IBinder token,
+ @NonNull String opPackageName);
+
+ void scheduleEnroll(int sensorId, @NonNull IBinder token, byte[] hardwareAuthToken, int userId,
+ @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
+ @Nullable Surface surface);
+
+ void cancelEnrollment(int sensorId, @NonNull IBinder token);
+
+ void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
+ @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName,
+ @Nullable Surface surface, int statsClient);
+
+ void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
+ int cookie, @NonNull ClientMonitorCallbackConverter callback,
+ @NonNull String opPackageName, boolean restricted, int statsClient, boolean isKeyguard);
+
+ void startPreparedClient(int sensorId, int cookie);
+
+ void cancelAuthentication(int sensorId, @NonNull IBinder token);
+
+ void scheduleRemove(int sensorId, @NonNull IBinder token,
+ @NonNull IFingerprintServiceReceiver receiver, int fingerId, int userId,
+ @NonNull String opPackageName);
+
+ boolean isHardwareDetected(int sensorId);
+
+ void rename(int sensorId, int fingerId, int userId, @NonNull String name);
+
+ @NonNull List<Fingerprint> getEnrolledFingerprints(int sensorId, int userId);
+
+ @LockoutTracker.LockoutMode int getLockoutModeForUser(int sensorId, int userId);
+
+ long getAuthenticatorId(int sensorId, int userId);
+
+ void onFingerDown(int sensorId, int x, int y, float minor, float major);
+
+ void onFingerUp(int sensorId);
+
+ void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller);
+
+ void dumpProto(int sensorId, @NonNull FileDescriptor fd);
+
+ void dumpInternal(int sensorId, @NonNull PrintWriter pw);
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index c87bfec85dc3..30cbf40398ab 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -66,6 +66,7 @@ import com.android.server.biometrics.sensors.PerformanceTracker;
import com.android.server.biometrics.sensors.RemovalConsumer;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
+import com.android.server.biometrics.sensors.fingerprint.ServiceProvider;
import org.json.JSONArray;
import org.json.JSONException;
@@ -83,14 +84,14 @@ import java.util.Map;
* Supports a single instance of the {@link android.hardware.biometrics.fingerprint.V2_1} or
* its extended minor versions.
*/
-public class Fingerprint21 implements IHwBinder.DeathRecipient {
+public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider {
private static final String TAG = "Fingerprint21";
private static final int ENROLL_TIMEOUT_SEC = 60;
final Context mContext;
private final IActivityTaskManager mActivityTaskManager;
- private final FingerprintSensorProperties mSensorProperties;
+ @NonNull private final FingerprintSensorProperties mSensorProperties;
private final BiometricScheduler mScheduler;
private final Handler mHandler;
private final LockoutResetDispatcher mLockoutResetDispatcher;
@@ -435,9 +436,6 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient {
@Nullable IUdfpsOverlayController getUdfpsOverlayController() {
return mUdfpsOverlayController;
}
- @LockoutTracker.LockoutMode public int getLockoutModeForUser(int userId) {
- return mLockoutTracker.getLockoutModeForUser(userId);
- }
private void scheduleLoadAuthenticatorIds() {
// Note that this can be performed on the scheduler (as opposed to being done immediately
@@ -466,7 +464,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient {
* correct.
*/
private void scheduleUpdateActiveUserWithoutHandler(int targetUserId) {
- final boolean hasEnrolled = !getEnrolledFingerprints(targetUserId).isEmpty();
+ final boolean hasEnrolled =
+ !getEnrolledFingerprints(mSensorProperties.sensorId, targetUserId).isEmpty();
final FingerprintUpdateActiveUserClient client =
new FingerprintUpdateActiveUserClient(mContext, mLazyDaemon, targetUserId,
mContext.getOpPackageName(), mSensorProperties.sensorId, mCurrentUserId,
@@ -481,7 +480,21 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient {
});
}
- public void scheduleResetLockout(int userId) {
+ @Override
+ public boolean containsSensor(int sensorId) {
+ return mSensorProperties.sensorId == sensorId;
+ }
+
+ @Override
+ @NonNull
+ public List<FingerprintSensorProperties> getSensorProperties() {
+ final List<FingerprintSensorProperties> properties = new ArrayList<>();
+ properties.add(mSensorProperties);
+ return properties;
+ }
+
+ @Override
+ public void scheduleResetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken) {
// Fingerprint2.1 keeps track of lockout in the framework. Let's just do it on the handler
// thread.
mHandler.post(() -> {
@@ -489,7 +502,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient {
});
}
- public void scheduleGenerateChallenge(@NonNull IBinder token,
+ @Override
+ public void scheduleGenerateChallenge(int sensorId, @NonNull IBinder token,
@NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName) {
mHandler.post(() -> {
final FingerprintGenerateChallengeClient client =
@@ -500,7 +514,9 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient {
});
}
- public void scheduleRevokeChallenge(@NonNull IBinder token, @NonNull String opPackageName) {
+ @Override
+ public void scheduleRevokeChallenge(int sensorId, @NonNull IBinder token,
+ @NonNull String opPackageName) {
mHandler.post(() -> {
final FingerprintRevokeChallengeClient client = new FingerprintRevokeChallengeClient(
mContext, mLazyDaemon, token, opPackageName, mSensorProperties.sensorId);
@@ -508,7 +524,9 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient {
});
}
- public void scheduleEnroll(@NonNull IBinder token, @NonNull byte[] hardwareAuthToken, int userId,
+ @Override
+ public void scheduleEnroll(int sensorId, @NonNull IBinder token,
+ @NonNull byte[] hardwareAuthToken, int userId,
@NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
@Nullable Surface surface) {
mHandler.post(() -> {
@@ -531,13 +549,15 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient {
});
}
- public void cancelEnrollment(@NonNull IBinder token) {
+ @Override
+ public void cancelEnrollment(int sensorId, @NonNull IBinder token) {
mHandler.post(() -> {
mScheduler.cancelEnrollment(token);
});
}
- public void scheduleFingerDetect(@NonNull IBinder token, int userId,
+ @Override
+ public void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
@NonNull ClientMonitorCallbackConverter listener, @NonNull String opPackageName,
@Nullable Surface surface, int statsClient) {
mHandler.post(() -> {
@@ -552,8 +572,9 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient {
});
}
- public void scheduleAuthenticate(@NonNull IBinder token, long operationId, int userId,
- int cookie, @NonNull ClientMonitorCallbackConverter listener,
+ @Override
+ public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
+ int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener,
@NonNull String opPackageName, boolean restricted, int statsClient,
boolean isKeyguard) {
mHandler.post(() -> {
@@ -569,19 +590,22 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient {
});
}
- public void startPreparedClient(int cookie) {
+ @Override
+ public void startPreparedClient(int sensorId, int cookie) {
mHandler.post(() -> {
mScheduler.startPreparedClient(cookie);
});
}
- public void cancelAuthentication(@NonNull IBinder token) {
+ @Override
+ public void cancelAuthentication(int sensorId, @NonNull IBinder token) {
mHandler.post(() -> {
mScheduler.cancelAuthentication(token);
});
}
- public void scheduleRemove(@NonNull IBinder token,
+ @Override
+ public void scheduleRemove(int sensorId, @NonNull IBinder token,
@NonNull IFingerprintServiceReceiver receiver, int fingerId, int userId,
@NonNull String opPackageName) {
mHandler.post(() -> {
@@ -599,7 +623,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
- final List<Fingerprint> enrolledList = getEnrolledFingerprints(userId);
+ final List<Fingerprint> enrolledList = getEnrolledFingerprints(
+ mSensorProperties.sensorId, userId);
final FingerprintInternalCleanupClient client = new FingerprintInternalCleanupClient(
mContext, mLazyDaemon, userId, mContext.getOpPackageName(),
mSensorProperties.sensorId, enrolledList, FingerprintUtils.getInstance(),
@@ -608,30 +633,37 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient {
});
}
- public boolean isHardwareDetected() {
+ @Override
+ public boolean isHardwareDetected(int sensorId) {
final IBiometricsFingerprint daemon = getDaemon();
return daemon != null;
}
- @NonNull public FingerprintSensorProperties getFingerprintSensorProperties() {
- return mSensorProperties;
- }
-
- public void rename(int fingerId, int userId, String name) {
+ @Override
+ public void rename(int sensorId, int fingerId, int userId, @NonNull String name) {
mHandler.post(() -> {
FingerprintUtils.getInstance().renameBiometricForUser(mContext, userId, fingerId, name);
});
}
- public List<Fingerprint> getEnrolledFingerprints(int userId) {
+ @Override
+ @NonNull
+ public List<Fingerprint> getEnrolledFingerprints(int sensorId, int userId) {
return FingerprintUtils.getInstance().getBiometricsForUser(mContext, userId);
}
- public long getAuthenticatorId(int userId) {
+ @Override
+ @LockoutTracker.LockoutMode public int getLockoutModeForUser(int sensorId, int userId) {
+ return mLockoutTracker.getLockoutModeForUser(userId);
+ }
+
+ @Override
+ public long getAuthenticatorId(int sensorId, int userId) {
return mAuthenticatorIds.get(userId);
}
- public void onFingerDown(int x, int y, float minor, float major) {
+ @Override
+ public void onFingerDown(int sensorId, int x, int y, float minor, float major) {
final ClientMonitor<?> client = mScheduler.getCurrentClient();
if (!(client instanceof Udfps)) {
Slog.w(TAG, "onFingerDown received during client: " + client);
@@ -641,7 +673,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient {
udfps.onFingerDown(x, y, minor, major);
}
- public void onFingerUp() {
+ @Override
+ public void onFingerUp(int sensorId) {
final ClientMonitor<?> client = mScheduler.getCurrentClient();
if (!(client instanceof Udfps)) {
Slog.w(TAG, "onFingerDown received during client: " + client);
@@ -651,11 +684,13 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient {
udfps.onFingerUp();
}
- public void setUdfpsOverlayController(IUdfpsOverlayController controller) {
+ @Override
+ public void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller) {
mUdfpsOverlayController = controller;
}
- public void dumpProto(FileDescriptor fd) {
+ @Override
+ public void dumpProto(int sensorId, FileDescriptor fd) {
PerformanceTracker tracker =
PerformanceTracker.getInstanceForSensorId(mSensorProperties.sensorId);
@@ -695,7 +730,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient {
tracker.clear();
}
- public void dumpInternal(@NonNull PrintWriter pw) {
+ @Override
+ public void dumpInternal(int sensorId, @NonNull PrintWriter pw) {
PerformanceTracker performanceTracker =
PerformanceTracker.getInstanceForSensorId(mSensorProperties.sensorId);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index 6d8f241adbdc..d68671bcc679 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -46,6 +46,7 @@ import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import java.util.ArrayList;
+import java.util.List;
import java.util.Random;
/**
@@ -397,8 +398,9 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
// Schedule this only after we invoke onClientFinished for the previous client, so that
// internal preemption logic is not run.
- mFingerprint21.scheduleAuthenticate(token, operationId, user, cookie,
- listener, opPackageName, restricted, statsClient, isKeyguard);
+ mFingerprint21.scheduleAuthenticate(mFingerprint21.mSensorProperties.sensorId, token,
+ operationId, user, cookie, listener, opPackageName, restricted, statsClient,
+ isKeyguard);
}
}
@@ -451,12 +453,14 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
@Override
@NonNull
- public FingerprintSensorProperties getFingerprintSensorProperties() {
- return mSensorProperties;
+ public List<FingerprintSensorProperties> getSensorProperties() {
+ final List<FingerprintSensorProperties> properties = new ArrayList<>();
+ properties.add(mSensorProperties);
+ return properties;
}
@Override
- public void onFingerDown(int x, int y, float minor, float major) {
+ public void onFingerDown(int sensorId, int x, int y, float minor, float major) {
mHandler.post(() -> {
Slog.d(TAG, "onFingerDown");
final AuthenticationConsumer lastAuthenticatedConsumer =
@@ -503,7 +507,7 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
}
@Override
- public void onFingerUp() {
+ public void onFingerUp(int sensorId) {
mHandler.post(() -> {
Slog.d(TAG, "onFingerUp");
@@ -558,7 +562,7 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage
// Things can happen before SysUI loads and sets the controller.
if (controller != null) {
Slog.d(TAG, "setDebugMessage: " + message);
- controller.setDebugMessage(message);
+ controller.setDebugMessage(mSensorProperties.sensorId, message);
}
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when sending message: " + message, e);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index 8087e15b540d..0658f957fecb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -79,7 +79,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
if (authenticated) {
resetFailedAttempts(getTargetUserId());
- UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
+ UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
mCallback.onClientFinished(this, true /* success */);
} else {
final @LockoutTracker.LockoutMode int lockoutMode =
@@ -92,7 +92,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
// Send the error, but do not invoke the FinishCallback yet. Since lockout is not
// controlled by the HAL, the framework must stop the sensor before finishing the
// client.
- UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
+ UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
onErrorInternal(errorCode, 0 /* vendorCode */, false /* finish */);
cancel();
}
@@ -111,7 +111,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
@Override
protected void startHalOperation() {
- UdfpsHelper.showUdfpsOverlay(mUdfpsOverlayController);
+ UdfpsHelper.showUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
try {
// GroupId was never used. In fact, groupId is always the same as userId.
getFreshDaemon().authenticate(mOperationId, getTargetUserId());
@@ -119,14 +119,14 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
Slog.e(TAG, "Remote exception when requesting auth", e);
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
- UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
+ UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
mCallback.onClientFinished(this, false /* success */);
}
}
@Override
protected void stopHalOperation() {
- UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
+ UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
try {
getFreshDaemon().cancel();
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
index 5865617f4a44..cad2214891a7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
@@ -61,7 +61,7 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint>
@Override
protected void stopHalOperation() {
- UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
+ UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
try {
getFreshDaemon().cancel();
} catch (RemoteException e) {
@@ -80,14 +80,14 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint>
@Override
protected void startHalOperation() {
- UdfpsHelper.showUdfpsOverlay(mUdfpsOverlayController);
+ UdfpsHelper.showUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
try {
getFreshDaemon().authenticate(0 /* operationId */, getTargetUserId());
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting auth", e);
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
- UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
+ UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
mCallback.onClientFinished(this, false /* success */);
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
index 1b9fae9cf91a..b1030bf367e8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
@@ -70,7 +70,7 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
@Override
protected void startHalOperation() {
- UdfpsHelper.showUdfpsOverlay(mUdfpsOverlayController);
+ UdfpsHelper.showUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
try {
// GroupId was never used. In fact, groupId is always the same as userId.
getFreshDaemon().enroll(mHardwareAuthToken, getTargetUserId(), mTimeoutSec);
@@ -78,14 +78,14 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
Slog.e(TAG, "Remote exception when requesting enroll", e);
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
- UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
+ UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
mCallback.onClientFinished(this, false /* success */);
}
}
@Override
protected void stopHalOperation() {
- UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
+ UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
try {
getFreshDaemon().cancel();
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/UdfpsHelper.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/UdfpsHelper.java
index c71ecbf7577d..0f1d6b462cac 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/UdfpsHelper.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/UdfpsHelper.java
@@ -62,23 +62,25 @@ public class UdfpsHelper {
}
}
- static void showUdfpsOverlay(@Nullable IUdfpsOverlayController udfpsOverlayController) {
+ static void showUdfpsOverlay(int sensorId,
+ @Nullable IUdfpsOverlayController udfpsOverlayController) {
if (udfpsOverlayController == null) {
return;
}
try {
- udfpsOverlayController.showUdfpsOverlay();
+ udfpsOverlayController.showUdfpsOverlay(sensorId);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when showing the UDFPS overlay", e);
}
}
- static void hideUdfpsOverlay(@Nullable IUdfpsOverlayController udfpsOverlayController) {
+ static void hideUdfpsOverlay(int sensorId,
+ @Nullable IUdfpsOverlayController udfpsOverlayController) {
if (udfpsOverlayController == null) {
return;
}
try {
- udfpsOverlayController.hideUdfpsOverlay();
+ udfpsOverlayController.hideUdfpsOverlay(sensorId);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when hiding the UDFPS overlay", e);
}
diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
index 626303001ba0..fa03e59f2f2e 100644
--- a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
+++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java
@@ -60,12 +60,12 @@ import android.net.ipsec.ike.IkeTrafficSelector;
import android.net.ipsec.ike.TunnelModeChildSessionParams;
import android.net.ipsec.ike.exceptions.IkeException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
-import android.net.util.IpRange;
import android.system.OsConstants;
import android.util.Log;
import com.android.internal.net.VpnProfile;
import com.android.internal.util.HexDump;
+import com.android.net.module.util.IpRange;
import java.net.Inet4Address;
import java.net.Inet6Address;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index f2f6dbe9bde5..6e6d848c2acc 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -58,11 +58,6 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
// If true, turn off TV upon standby. False by default.
private boolean mAutoTvOff;
- // Local active port number used for Routing Control.
- // Default 0 means HOME is the current active path. Temp solution only.
- // TODO(amyjojo): adding system constants for input ports to TIF mapping.
- private int mLocalActivePath = 0;
-
// Determines what action should be taken upon receiving Routing Control messages.
@VisibleForTesting
protected HdmiProperties.playback_device_action_on_routing_control_values
@@ -438,16 +433,6 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
checkIfPendingActionsCleared();
}
- private void routeToPort(int portId) {
- // TODO(AMYJOJO): route to specific input of the port
- mLocalActivePath = portId;
- }
-
- @VisibleForTesting
- protected int getLocalActivePath() {
- return mLocalActivePath;
- }
-
@Override
protected void dump(final IndentingPrintWriter pw) {
super.dump(pw);
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 7c98c6c7947b..4a4c39d7d40e 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -233,7 +233,7 @@ public class InputManagerService extends IInputManager.Stub
private static native void nativeToggleCapsLock(long ptr, int deviceId);
private static native void nativeDisplayRemoved(long ptr, int displayId);
private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen);
- private static native void nativeSetSystemUiVisibility(long ptr, int visibility);
+ private static native void nativeSetSystemUiLightsOut(long ptr, boolean lightsOut);
private static native void nativeSetFocusedApplication(long ptr,
int displayId, InputApplicationHandle application);
private static native void nativeSetFocusedDisplay(long ptr, int displayId);
@@ -1560,8 +1560,8 @@ public class InputManagerService extends IInputManager.Stub
nativeSetInputDispatchMode(mPtr, enabled, frozen);
}
- public void setSystemUiVisibility(int visibility) {
- nativeSetSystemUiVisibility(mPtr, visibility);
+ public void setSystemUiLightsOut(boolean lightsOut) {
+ nativeSetSystemUiLightsOut(mPtr, lightsOut);
}
/**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index a44fabbeb2d3..2eccaf1434b4 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -17,6 +17,9 @@ package com.android.server.inputmethod;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.CLIENTS;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ELAPSED_REALTIME_NANOS;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorTraceFileProto.ENTRY;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -96,12 +99,15 @@ import android.text.style.SuggestionSpan;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
+import android.util.Log;
import android.util.LruCache;
import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.imetracing.ImeTracing;
+import android.util.proto.ProtoOutputStream;
import android.view.ContextThemeWrapper;
import android.view.DisplayInfo;
import android.view.IWindowManager;
@@ -4032,6 +4038,55 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE_FROM_WINDOW, windowToken).sendToTarget();
}
+ /**
+ * Starting point for dumping the IME tracing information in proto format.
+ *
+ * @param clientProtoDump dump information from the IME client side
+ */
+ @BinderThread
+ @Override
+ public void startProtoDump(byte[] clientProtoDump) {
+ if (!ImeTracing.getInstance().isAvailable() || !ImeTracing.getInstance().isEnabled()) {
+ return;
+ }
+ if (clientProtoDump == null && mCurClient == null) {
+ return;
+ }
+
+ ProtoOutputStream proto = new ProtoOutputStream();
+ final long token = proto.start(ENTRY);
+ proto.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
+ // TODO: get server side dump
+ if (clientProtoDump != null) {
+ proto.write(CLIENTS, clientProtoDump);
+ } else {
+ IBinder client = null;
+
+ synchronized (mMethodMap) {
+ if (mCurClient != null && mCurClient.client != null) {
+ client = mCurClient.client.asBinder();
+ }
+ }
+
+ if (client != null) {
+ try {
+ proto.write(CLIENTS,
+ TransferPipe.dumpAsync(client, ImeTracing.PROTO_ARG));
+ } catch (IOException | RemoteException e) {
+ Log.e(TAG, "Exception while collecting client side ime dump", e);
+ }
+ }
+ }
+ proto.end(token);
+ ImeTracing.getInstance().addToBuffer(proto);
+ }
+
+ @BinderThread
+ @Override
+ public boolean isImeTraceEnabled() {
+ return ImeTracing.getInstance().isEnabled();
+ }
+
@BinderThread
private void notifyUserAction(@NonNull IBinder token) {
if (DEBUG) {
@@ -5426,6 +5481,21 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return mService.handleShellCommandSetInputMethod(this);
case "reset":
return mService.handleShellCommandResetInputMethod(this);
+ case "tracing":
+ int result = ImeTracing.getInstance().onShellCommand(this);
+ boolean isImeTraceEnabled = ImeTracing.getInstance().isEnabled();
+ for (ClientState state : mService.mClients.values()) {
+ if (state != null) {
+ try {
+ state.client.setImeTraceEnabled(isImeTraceEnabled);
+ } catch (RemoteException e) {
+ Log.e(TAG,
+ "Error while trying to enable/disable ime "
+ + "trace on client window", e);
+ }
+ }
+ }
+ return result;
default:
getOutPrintWriter().println("Unknown command: " + imeCommand);
return ShellCommandResult.FAILURE;
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index b518eb1ab6d0..a6ca25b0e6c1 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -1805,5 +1805,16 @@ public final class MultiClientInputMethodManagerService {
mUserDataMap.dump(fd, ipw, args);
}
}
+
+ @BinderThread
+ @Override
+ public void startProtoDump(byte[] clientProtoDump) throws RemoteException {
+ }
+
+ @BinderThread
+ @Override
+ public boolean isImeTraceEnabled() throws RemoteException {
+ return false;
+ }
}
}
diff --git a/services/core/java/com/android/server/media/MediaShellCommand.java b/services/core/java/com/android/server/media/MediaShellCommand.java
index 20df271a1de2..69c57a9a5d74 100644
--- a/services/core/java/com/android/server/media/MediaShellCommand.java
+++ b/services/core/java/com/android/server/media/MediaShellCommand.java
@@ -38,6 +38,7 @@ import android.view.KeyEvent;
import java.io.BufferedReader;
import java.io.IOException;
+import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.List;
@@ -53,11 +54,13 @@ public class MediaShellCommand extends ShellCommand {
private ISessionManager mSessionService;
private PrintWriter mWriter;
private PrintWriter mErrorWriter;
+ private InputStream mInput;
@Override
public int onCommand(String cmd) {
mWriter = getOutPrintWriter();
mErrorWriter = getErrPrintWriter();
+ mInput = getRawInputStream();
if (TextUtils.isEmpty(cmd)) {
return handleDefaultCommands(cmd);
@@ -189,6 +192,10 @@ public class MediaShellCommand extends ShellCommand {
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
}
+ void log(String code, String msg) {
+ mWriter.println(code + " " + msg);
+ }
+
void showError(String errMsg) {
onHelp();
mErrorWriter.println(errMsg);
@@ -273,11 +280,14 @@ public class MediaShellCommand extends ShellCommand {
cbThread.start();
try {
- InputStreamReader converter = new InputStreamReader(System.in);
+ InputStreamReader converter = new InputStreamReader(mInput);
BufferedReader in = new BufferedReader(converter);
String line;
- while ((line = in.readLine()) != null) {
+ while (true) {
+ mWriter.flush();
+ mErrorWriter.flush();
+ if ((line = in.readLine()) == null) break;
boolean addNewline = true;
if (line.length() <= 0) {
addNewline = false;
@@ -297,7 +307,7 @@ public class MediaShellCommand extends ShellCommand {
synchronized (this) {
if (addNewline) {
- System.out.println("");
+ mWriter.println("");
}
printUsageMessage();
}
diff --git a/services/core/java/com/android/server/media/VolumeCtrl.java b/services/core/java/com/android/server/media/VolumeCtrl.java
index 7a2666566ea2..d516d963e866 100644
--- a/services/core/java/com/android/server/media/VolumeCtrl.java
+++ b/services/core/java/com/android/server/media/VolumeCtrl.java
@@ -32,6 +32,8 @@ import com.android.internal.os.BaseCommand;
public class VolumeCtrl {
private static final String TAG = "VolumeCtrl";
+ private static final String LOG_V = "[V]";
+ private static final String LOG_E = "[E]";
// --stream affects --set, --adj or --get options.
// --show affects --set and --adj options.
@@ -80,21 +82,22 @@ public class VolumeCtrl {
break;
case "--get":
doGet = true;
- log(LOG_V, "will get volume");
+ cmd.log(LOG_V, "will get volume");
break;
case "--stream":
stream = Integer.decode(cmd.getNextArgRequired()).intValue();
- log(LOG_V, "will control stream=" + stream + " (" + streamName(stream) + ")");
+ cmd.log(LOG_V,
+ "will control stream=" + stream + " (" + streamName(stream) + ")");
break;
case "--set":
volIndex = Integer.decode(cmd.getNextArgRequired()).intValue();
mode = VOLUME_CONTROL_MODE_SET;
- log(LOG_V, "will set volume to index=" + volIndex);
+ cmd.log(LOG_V, "will set volume to index=" + volIndex);
break;
case "--adj":
mode = VOLUME_CONTROL_MODE_ADJUST;
adjustment = cmd.getNextArgRequired();
- log(LOG_V, "will adjust volume");
+ cmd.log(LOG_V, "will adjust volume");
break;
default:
throw new IllegalArgumentException("Unknown argument " + option);
@@ -122,11 +125,11 @@ public class VolumeCtrl {
//----------------------------------------
// Test initialization
- log(LOG_V, "Connecting to AudioService");
+ cmd.log(LOG_V, "Connecting to AudioService");
IAudioService audioService = IAudioService.Stub.asInterface(ServiceManager.checkService(
Context.AUDIO_SERVICE));
if (audioService == null) {
- System.err.println(BaseCommand.NO_SYSTEM_ERROR_CODE);
+ cmd.log(LOG_E, BaseCommand.NO_SYSTEM_ERROR_CODE);
throw new AndroidException(
"Can't connect to audio service; is the system running?");
}
@@ -152,23 +155,12 @@ public class VolumeCtrl {
audioService.adjustStreamVolume(stream, adjDir, flag, pack);
}
if (doGet) {
- log(LOG_V, "volume is " + audioService.getStreamVolume(stream)
+ cmd.log(LOG_V, "volume is " + audioService.getStreamVolume(stream)
+ " in range [" + audioService.getStreamMinVolume(stream)
+ ".." + audioService.getStreamMaxVolume(stream) + "]");
}
}
- //--------------------------------------------
- // Utilities
-
- static final String LOG_V = "[v]";
- static final String LOG_W = "[w]";
- static final String LOG_OK = "[ok]";
-
- static void log(String code, String msg) {
- System.out.println(code + " " + msg);
- }
-
static String streamName(int stream) {
try {
return AudioSystem.STREAM_NAMES[stream];
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 60737bf77c48..949dcb254d21 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2081,7 +2081,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mRelinquished = true;
- return mPm.new VerificationParams(user, stageDir, localObserver, params,
+ // TODO(b/169375643): Remove this workaround once b/161121612 is fixed.
+ PackageInstaller.SessionParams copiedParams = params.copy();
+ if (params.isStaged) {
+ // This is called by the pre-reboot verification. Don't enable rollback here since
+ // it has been enabled when pre-reboot verification starts.
+ copiedParams.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
+ }
+ return mPm.new VerificationParams(user, stageDir, localObserver, copiedParams,
mInstallSource, mInstallerUid, mSigningDetails, sessionId);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 3e7304b722fc..4450f9a1a3b7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -25949,6 +25949,15 @@ public class PackageManagerService extends IPackageManager.Stub
mPermissionManager.writeStateToPackageSettingsTEMP();
mSettings.writeLPr();
}
+
+ @Override
+ public void holdLock(int durationMs) {
+ mContext.enforceCallingPermission(
+ Manifest.permission.INJECT_EVENTS, "holdLock requires shell identity");
+ synchronized (mLock) {
+ SystemClock.sleep(durationMs);
+ }
+ }
}
interface PackageSender {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 35b14490eba2..df283e210be8 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1552,6 +1552,17 @@ public class PhoneWindowManager implements WindowManagerPolicy {
startActivityAsUser(intent, UserHandle.CURRENT);
}
+ private void toggleNotificationPanel() {
+ IStatusBarService statusBarService = getStatusBarService();
+ if (statusBarService != null) {
+ try {
+ statusBarService.togglePanel();
+ } catch (RemoteException e) {
+ // do nothing.
+ }
+ }
+ }
+
private void showPictureInPictureMenu(KeyEvent event) {
if (DEBUG_INPUT) Log.d(TAG, "showPictureInPictureMenu event=" + event);
mHandler.removeMessages(MSG_SHOW_PICTURE_IN_PICTURE_MENU);
@@ -1696,14 +1707,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
launchAssistAction(null, deviceId);
break;
case LONG_PRESS_HOME_NOTIFICATION_PANEL:
- IStatusBarService statusBarService = getStatusBarService();
- if (statusBarService != null) {
- try {
- statusBarService.togglePanel();
- } catch (RemoteException e) {
- // do nothing.
- }
- }
+ toggleNotificationPanel();
break;
default:
Log.w(TAG, "Undefined long press on home behavior: "
@@ -2807,6 +2811,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
msg.sendToTarget();
}
return -1;
+ } else if (keyCode == KeyEvent.KEYCODE_NOTIFICATION) {
+ if (!down) {
+ toggleNotificationPanel();
+ }
+ return -1;
}
// Toggle Caps Lock on META-ALT.
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 6044ee18614a..60da8e5c7b70 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -5408,6 +5408,22 @@ public final class PowerManagerService extends SystemService
}
@Override // Binder call
+ public boolean isAmbientDisplaySuppressedForTokenByApp(@NonNull String token, int appUid) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.READ_DREAM_STATE, null);
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.READ_DREAM_SUPPRESSION, null);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return isAmbientDisplayAvailable()
+ && mAmbientDisplaySuppressionController.isSuppressed(token, appUid);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
public boolean isAmbientDisplaySuppressed() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_DREAM_STATE, null);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 67924307f009..42fb13389b04 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4465,6 +4465,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
detachChildren();
}
+ if (app != null) {
+ app.invalidateOomScoreReferenceState(false /* computeNow */);
+ }
switch (state) {
case RESUMED:
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 2dc22ecfc022..e65be41f44cd 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -499,9 +499,6 @@ public abstract class ActivityTaskManagerInternal {
/** @return the process for the top-most resumed activity in the system. */
public abstract WindowProcessController getTopApp();
- /** Generate oom-score-adjustment rank for all tasks in the system based on z-order. */
- public abstract void rankTaskLayersIfNeeded();
-
/** Destroy all activities. */
public abstract void scheduleDestroyAllActivities(String reason);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 15669cbe227a..bd5ab1b298ee 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -7187,16 +7187,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
- @HotPath(caller = HotPath.OOM_ADJUSTMENT)
- @Override
- public void rankTaskLayersIfNeeded() {
- synchronized (mGlobalLockWithoutBoost) {
- if (mRootWindowContainer != null) {
- mRootWindowContainer.rankTaskLayersIfNeeded();
- }
- }
- }
-
@Override
public void scheduleDestroyAllActivities(String reason) {
synchronized (mGlobalLock) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index b3e69d4847f7..1153c4666fbe 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -193,7 +193,6 @@ import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
-import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
@@ -552,11 +551,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
private SurfaceControl mParentSurfaceControl;
private InputWindowHandle mPortalWindowHandle;
- // Last systemUiVisibility we received from status bar.
- private int mLastStatusBarVisibility = 0;
- // Last systemUiVisibility we dispatched to windows.
- private int mLastDispatchedSystemUiVisibility = 0;
-
/** Corner radius that windows should have in order to match the display. */
private final float mWindowCornerRadius;
@@ -2907,10 +2901,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
pw.print(" mLastFocus="); pw.println(mLastFocus);
}
pw.print(" mFocusedApp="); pw.println(mFocusedApp);
- if (mLastStatusBarVisibility != 0) {
- pw.print(" mLastStatusBarVisibility=0x");
- pw.println(Integer.toHexString(mLastStatusBarVisibility));
- }
if (mFixedRotationLaunchingApp != null) {
pw.println(" mFixedRotationLaunchingApp=" + mFixedRotationLaunchingApp);
}
@@ -3770,50 +3760,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return win != null;
}
- void hideTransientBars() {
- // TODO(b/118118435): Remove this after migration
- final int transientFlags = View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT;
- statusBarVisibilityChanged(mLastStatusBarVisibility & ~transientFlags);
-
- getInsetsPolicy().hideTransient();
- }
-
- void statusBarVisibilityChanged(int visibility) {
- mLastStatusBarVisibility = visibility;
- updateStatusBarVisibilityLocked(visibility);
- }
-
- private boolean updateStatusBarVisibilityLocked(int visibility) {
- if (mLastDispatchedSystemUiVisibility == visibility) {
- return false;
- }
- final int globalDiff = (visibility ^ mLastDispatchedSystemUiVisibility)
- // We are only interested in differences of one of the
- // clearable flags...
- & View.SYSTEM_UI_CLEARABLE_FLAGS
- // ...if it has actually been cleared.
- & ~visibility;
-
- mLastDispatchedSystemUiVisibility = visibility;
- if (isDefaultDisplay) {
- mWmService.mInputManager.setSystemUiVisibility(visibility);
- }
- updateSystemUiVisibility(visibility, globalDiff);
- return true;
- }
-
- void updateSystemUiVisibility(int visibility, int globalDiff) {
- forAllWindows(w -> {
- final int curValue = w.mSystemUiVisibility;
- final int diff = (curValue ^ visibility) & globalDiff;
- final int newValue = (curValue & ~diff) | (visibility & diff);
- if (newValue != curValue) {
- w.mSeq++;
- w.mSystemUiVisibility = newValue;
- }
- }, true /* traverseTopToBottom */);
- }
-
void onWindowFreezeTimeout() {
Slog.w(TAG_WM, "Window freeze timeout expired.");
mWmService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index e54da9e99852..dce798e81a86 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -43,6 +43,7 @@ import static android.view.InsetsState.ITYPE_TOP_GESTURES;
import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
+import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE;
@@ -156,6 +157,7 @@ import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.Surface;
import android.view.View;
+import android.view.ViewDebug;
import android.view.WindowInsets.Side;
import android.view.WindowInsets.Side.InsetsSide;
import android.view.WindowInsets.Type;
@@ -1445,9 +1447,9 @@ public class DisplayPolicy {
boolean getLayoutHint(LayoutParams attrs, WindowToken windowToken, Rect outFrame,
Rect outContentInsets, Rect outStableInsets,
DisplayCutout.ParcelableWrapper outDisplayCutout) {
- final int fl = PolicyControl.getWindowFlags(null, attrs);
+ final int fl = attrs.flags;
final int pfl = attrs.privateFlags;
- final int sysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
+ final int sysUiVis = attrs.systemUiVisibility | attrs.subtreeSystemUiVisibility;
final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0;
final boolean layoutInScreenAndInsetDecor = layoutInScreen
@@ -2001,7 +2003,7 @@ public class DisplayPolicy {
final WindowManager.LayoutParams attrs = win.getAttrs();
final int type = attrs.type;
- final int fl = PolicyControl.getWindowFlags(win, attrs);
+ final int fl = attrs.flags;
final int pfl = attrs.privateFlags;
final int sim = attrs.softInputMode;
@@ -2243,7 +2245,7 @@ public class DisplayPolicy {
final boolean affectsSystemUi = win.canAffectSystemUiFlags();
if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi);
mService.mPolicy.applyKeyguardPolicyLw(win, imeTarget);
- final int fl = PolicyControl.getWindowFlags(win, attrs);
+ final int fl = attrs.flags;
if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi
&& attrs.type == TYPE_INPUT_METHOD) {
mForcingShowNavBar = true;
@@ -2418,8 +2420,7 @@ public class DisplayPolicy {
return false;
}
final LayoutParams attrs = mTopFullscreenOpaqueWindowState.getAttrs();
- final int fl = PolicyControl.getWindowFlags(null, attrs);
- final int sysui = PolicyControl.getSystemUiVisibility(null, attrs);
+ final int fl = attrs.flags;
final InsetsSource request = mTopFullscreenOpaqueWindowState.getRequestedInsetsState()
.peekSource(ITYPE_STATUS_BAR);
if (WindowManagerDebugConfig.DEBUG) {
@@ -2952,9 +2953,9 @@ public class DisplayPolicy {
mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
- final int fullscreenAppearance = updateLightStatusBarLw(0 /* vis */,
+ final int fullscreenAppearance = updateLightStatusBarLw(0 /* appearance */,
mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
- final int dockedAppearance = updateLightStatusBarLw(0 /* vis */,
+ final int dockedAppearance = updateLightStatusBarLw(0 /* appearance */,
mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
final boolean inSplitScreen =
mService.mRoot.getDefaultTaskDisplayArea().isSplitScreenModeActivated();
@@ -3025,6 +3026,10 @@ public class DisplayPolicy {
}
});
+ if (mDisplayContent.isDefaultDisplay) {
+ mService.mInputManager.setSystemUiLightsOut(
+ isFullscreen || (appearance & APPEARANCE_LOW_PROFILE_BARS) != 0);
+ }
return true;
}
@@ -3037,9 +3042,7 @@ public class DisplayPolicy {
// If the top fullscreen-or-dimming window is also the top fullscreen, respect
// its light flag.
appearance &= ~APPEARANCE_LIGHT_STATUS_BARS;
- final int legacyAppearance = InsetsFlags.getAppearance(
- PolicyControl.getSystemUiVisibility(statusColorWin, null));
- appearance |= (statusColorWin.mAttrs.insetsFlags.appearance | legacyAppearance)
+ appearance |= statusColorWin.mAttrs.insetsFlags.appearance
& APPEARANCE_LIGHT_STATUS_BARS;
} else if (statusColorWin.isDimming()) {
// Otherwise if it's dimming, clear the light flag.
@@ -3062,8 +3065,8 @@ public class DisplayPolicy {
final boolean imeWindowCanNavColorWindow = imeWindow != null
&& imeWindow.isVisibleLw()
&& navBarPosition == NAV_BAR_BOTTOM
- && (PolicyControl.getWindowFlags(imeWindow, null)
- & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
+ && (imeWindow.mAttrs.flags
+ & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
if (opaque != null && opaqueOrDimming == opaque) {
// If the top fullscreen-or-dimming window is also the top fullscreen, respect it
@@ -3085,7 +3088,7 @@ public class DisplayPolicy {
// The IME window and the dimming window are competing. Check if the dimming window can be
// IME target or not.
- if (LayoutParams.mayUseInputMethod(PolicyControl.getWindowFlags(opaqueOrDimming, null))) {
+ if (LayoutParams.mayUseInputMethod(opaqueOrDimming.mAttrs.flags)) {
// The IME window is above the dimming window.
return imeWindow;
} else {
@@ -3359,22 +3362,30 @@ public class DisplayPolicy {
pw.print(prefix); pw.print("mHdmiPlugged="); pw.println(mHdmiPlugged);
if (mLastDisableFlags != 0) {
pw.print(prefix); pw.print("mLastDisableFlags=0x");
- pw.print(Integer.toHexString(mLastDisableFlags));
+ pw.println(Integer.toHexString(mLastDisableFlags));
+ }
+ if (mLastAppearance != 0) {
+ pw.print(prefix); pw.print("mLastAppearance=");
+ pw.println(ViewDebug.flagsToString(InsetsFlags.class, "appearance", mLastAppearance));
+ }
+ if (mLastBehavior != 0) {
+ pw.print(prefix); pw.print("mLastBehavior=");
+ pw.println(ViewDebug.flagsToString(InsetsFlags.class, "behavior", mLastBehavior));
}
pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
- pw.print(" mDreamingLockscreen="); pw.print(mDreamingLockscreen);
+ pw.print(" mDreamingLockscreen="); pw.println(mDreamingLockscreen);
if (mStatusBar != null) {
- pw.print(prefix); pw.print("mStatusBar="); pw.print(mStatusBar);
+ pw.print(prefix); pw.print("mStatusBar="); pw.println(mStatusBar);
}
if (mStatusBarAlt != null) {
- pw.print(prefix); pw.print("mStatusBarAlt="); pw.print(mStatusBarAlt);
+ pw.print(prefix); pw.print("mStatusBarAlt="); pw.println(mStatusBarAlt);
pw.print(prefix); pw.print("mStatusBarAltPosition=");
pw.println(mStatusBarAltPosition);
}
if (mNotificationShade != null) {
- pw.print(prefix); pw.print("mExpandedPanel="); pw.print(mNotificationShade);
+ pw.print(prefix); pw.print("mExpandedPanel="); pw.println(mNotificationShade);
}
- pw.print(" isKeyguardShowing="); pw.println(isKeyguardShowing());
+ pw.print(prefix); pw.print("isKeyguardShowing="); pw.println(isKeyguardShowing());
if (mNavigationBar != null) {
pw.print(prefix); pw.print("mNavigationBar="); pw.println(mNavigationBar);
pw.print(prefix); pw.print("mNavBarOpacityMode="); pw.println(mNavBarOpacityMode);
@@ -3415,9 +3426,9 @@ public class DisplayPolicy {
}
pw.print(prefix); pw.print("mTopIsFullscreen="); pw.println(mTopIsFullscreen);
pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
- pw.print(prefix); pw.print("mRemoteInsetsControllerControlsSystemBars");
- pw.print(mDisplayContent.getInsetsPolicy().getRemoteInsetsControllerControlsSystemBars());
pw.print(" mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
+ pw.print(prefix); pw.print("mRemoteInsetsControllerControlsSystemBars=");
+ pw.println(mDisplayContent.getInsetsPolicy().getRemoteInsetsControllerControlsSystemBars());
pw.print(prefix); pw.println("Looper state:");
mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + " ");
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index f0f338534ed2..1d8cdf7e773c 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -138,8 +138,9 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider {
&& dcTarget.getParentWindow() == mImeTargetFromIme
&& dcTarget.mSubLayer > mImeTargetFromIme.getWindow().mSubLayer)
|| mImeTargetFromIme == mDisplayContent.getImeFallback()
+ || mImeTargetFromIme == mDisplayContent.mInputMethodInputTarget
|| controlTarget == mImeTargetFromIme
- && (mImeTargetFromIme.getWindow() == null
+ && (mImeTargetFromIme.getWindow() == null
|| !mImeTargetFromIme.getWindow().isClosing());
}
diff --git a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
index 8b1a0c93cfa3..02dad3978d42 100644
--- a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
@@ -28,6 +28,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.drawable.ColorDrawable;
import android.os.Binder;
@@ -46,6 +47,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
+import android.view.WindowInsets;
import android.view.WindowInsets.Type;
import android.view.WindowManager;
import android.view.animation.Animation;
@@ -134,11 +136,8 @@ public class ImmersiveModeConfirmation {
boolean userSetupComplete, boolean navBarEmpty) {
mHandler.removeMessages(H.SHOW);
if (isImmersiveMode) {
- final boolean disabled = PolicyControl.disableImmersiveConfirmation(pkg);
- if (DEBUG) Slog.d(TAG, String.format("immersiveModeChanged() disabled=%s sConfirmed=%s",
- disabled, sConfirmed));
- if (!disabled
- && (DEBUG_SHOW_EVERY_TIME || !sConfirmed)
+ if (DEBUG) Slog.d(TAG, "immersiveModeChanged() sConfirmed=" + sConfirmed);
+ if ((DEBUG_SHOW_EVERY_TIME || !sConfirmed)
&& userSetupComplete
&& !mVrModeEnabled
&& !navBarEmpty
@@ -339,6 +338,13 @@ public class ImmersiveModeConfirmation {
public boolean onTouchEvent(MotionEvent motion) {
return true;
}
+
+ @Override
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ // we will be hiding the nav bar, so layout as if it's already hidden
+ return new WindowInsets.Builder(insets).setInsets(
+ Type.systemBars(), Insets.NONE).build();
+ }
}
/**
@@ -359,10 +365,6 @@ public class ImmersiveModeConfirmation {
mClingWindow = new ClingWindowView(mContext, mConfirm);
- // we will be hiding the nav bar, so layout as if it's already hidden
- mClingWindow.setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
-
// show the confirmation
WindowManager.LayoutParams lp = getClingWindowLayoutParams();
getWindowManager().addView(mClingWindow, lp);
diff --git a/services/core/java/com/android/server/wm/PolicyControl.java b/services/core/java/com/android/server/wm/PolicyControl.java
deleted file mode 100644
index 61b6e0b25961..000000000000
--- a/services/core/java/com/android/server/wm/PolicyControl.java
+++ /dev/null
@@ -1,270 +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.server.wm;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.ArraySet;
-import android.util.Slog;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-
-/**
- * Runtime adjustments applied to the global window policy.
- *
- * This includes forcing immersive mode behavior for one or both system bars (based on a package
- * list) and permanently disabling immersive mode confirmations for specific packages.
- *
- * Control by setting {@link Settings.Global#POLICY_CONTROL} to one or more name-value pairs.
- * e.g.
- * to force immersive mode everywhere:
- * "immersive.full=*"
- * to force transient status for all apps except a specific package:
- * "immersive.status=apps,-com.package"
- * to disable the immersive mode confirmations for specific packages:
- * "immersive.preconfirms=com.package.one,com.package.two"
- *
- * Separate multiple name-value pairs with ':'
- * e.g. "immersive.status=apps:immersive.preconfirms=*"
- */
-class PolicyControl {
- private static final String TAG = "PolicyControl";
- private static final boolean DEBUG = false;
-
- @VisibleForTesting
- static final String NAME_IMMERSIVE_FULL = "immersive.full";
- private static final String NAME_IMMERSIVE_STATUS = "immersive.status";
- private static final String NAME_IMMERSIVE_NAVIGATION = "immersive.navigation";
- private static final String NAME_IMMERSIVE_PRECONFIRMATIONS = "immersive.preconfirms";
-
- private static String sSettingValue;
- private static Filter sImmersivePreconfirmationsFilter;
- private static Filter sImmersiveStatusFilter;
- private static Filter sImmersiveNavigationFilter;
-
- static int getSystemUiVisibility(WindowState win, LayoutParams attrs) {
- attrs = attrs != null ? attrs : win.getAttrs();
- int vis = win != null ? win.getSystemUiVisibility()
- : (attrs.systemUiVisibility | attrs.subtreeSystemUiVisibility);
- if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
- vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
- | View.SYSTEM_UI_FLAG_FULLSCREEN;
- if (attrs.isFullscreen()) {
- vis |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
- }
- vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.STATUS_BAR_TRANSLUCENT);
- }
- if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)) {
- vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
- if (attrs.isFullscreen()) {
- vis |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
- }
- vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.NAVIGATION_BAR_TRANSLUCENT);
- }
- return vis;
- }
-
- static int getWindowFlags(WindowState win, LayoutParams attrs) {
- attrs = attrs != null ? attrs : win.getAttrs();
- int flags = attrs.flags;
- if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
- flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
- flags &= ~(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
- | WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
- }
- if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)) {
- flags &= ~WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
- }
- return flags;
- }
-
- static int adjustClearableFlags(WindowState win, int clearableFlags) {
- final LayoutParams attrs = win != null ? win.getAttrs() : null;
- if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
- clearableFlags &= ~View.SYSTEM_UI_FLAG_FULLSCREEN;
- }
- return clearableFlags;
- }
-
- static boolean disableImmersiveConfirmation(String pkg) {
- return (sImmersivePreconfirmationsFilter != null
- && sImmersivePreconfirmationsFilter.matches(pkg))
- || ActivityManager.isRunningInTestHarness();
- }
-
- static boolean reloadFromSetting(Context context) {
- if (DEBUG) Slog.d(TAG, "reloadFromSetting()");
- String value = null;
- try {
- value = Settings.Global.getStringForUser(context.getContentResolver(),
- Settings.Global.POLICY_CONTROL,
- UserHandle.USER_CURRENT);
- if (sSettingValue == value || sSettingValue != null && sSettingValue.equals(value)) {
- return false;
- }
- setFilters(value);
- sSettingValue = value;
- } catch (Throwable t) {
- Slog.w(TAG, "Error loading policy control, value=" + value, t);
- return false;
- }
- return true;
- }
-
- static void dump(String prefix, PrintWriter pw) {
- dump("sImmersiveStatusFilter", sImmersiveStatusFilter, prefix, pw);
- dump("sImmersiveNavigationFilter", sImmersiveNavigationFilter, prefix, pw);
- dump("sImmersivePreconfirmationsFilter", sImmersivePreconfirmationsFilter, prefix, pw);
- }
-
- private static void dump(String name, Filter filter, String prefix, PrintWriter pw) {
- pw.print(prefix); pw.print("PolicyControl."); pw.print(name); pw.print('=');
- if (filter == null) {
- pw.println("null");
- } else {
- filter.dump(pw); pw.println();
- }
- }
-
- @VisibleForTesting
- static void setFilters(String value) {
- if (DEBUG) Slog.d(TAG, "setFilters: " + value);
- sImmersiveStatusFilter = null;
- sImmersiveNavigationFilter = null;
- sImmersivePreconfirmationsFilter = null;
- if (value != null) {
- String[] nvps = value.split(":");
- for (String nvp : nvps) {
- int i = nvp.indexOf('=');
- if (i == -1) continue;
- String n = nvp.substring(0, i);
- String v = nvp.substring(i + 1);
- if (n.equals(NAME_IMMERSIVE_FULL)) {
- Filter f = Filter.parse(v);
- sImmersiveStatusFilter = sImmersiveNavigationFilter = f;
- if (sImmersivePreconfirmationsFilter == null) {
- sImmersivePreconfirmationsFilter = f;
- }
- } else if (n.equals(NAME_IMMERSIVE_STATUS)) {
- Filter f = Filter.parse(v);
- sImmersiveStatusFilter = f;
- } else if (n.equals(NAME_IMMERSIVE_NAVIGATION)) {
- Filter f = Filter.parse(v);
- sImmersiveNavigationFilter = f;
- if (sImmersivePreconfirmationsFilter == null) {
- sImmersivePreconfirmationsFilter = f;
- }
- } else if (n.equals(NAME_IMMERSIVE_PRECONFIRMATIONS)) {
- Filter f = Filter.parse(v);
- sImmersivePreconfirmationsFilter = f;
- }
- }
- }
- if (DEBUG) {
- Slog.d(TAG, "immersiveStatusFilter: " + sImmersiveStatusFilter);
- Slog.d(TAG, "immersiveNavigationFilter: " + sImmersiveNavigationFilter);
- Slog.d(TAG, "immersivePreconfirmationsFilter: " + sImmersivePreconfirmationsFilter);
- }
- }
-
- private static class Filter {
- private static final String ALL = "*";
- private static final String APPS = "apps";
-
- private final ArraySet<String> mAllowlist;
- private final ArraySet<String> mDenylist;
-
- private Filter(ArraySet<String> allowlist, ArraySet<String> denylist) {
- mAllowlist = allowlist;
- mDenylist = denylist;
- }
-
- boolean matches(LayoutParams attrs) {
- if (attrs == null) return false;
- boolean isApp = attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
- && attrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
- if (isApp && mDenylist.contains(APPS)) return false;
- if (onDenylist(attrs.packageName)) return false;
- if (isApp && mAllowlist.contains(APPS)) return true;
- return onAllowlist(attrs.packageName);
- }
-
- boolean matches(String packageName) {
- return !onDenylist(packageName) && onAllowlist(packageName);
- }
-
- private boolean onDenylist(String packageName) {
- return mDenylist.contains(packageName) || mDenylist.contains(ALL);
- }
-
- private boolean onAllowlist(String packageName) {
- return mAllowlist.contains(ALL) || mAllowlist.contains(packageName);
- }
-
- void dump(PrintWriter pw) {
- pw.print("Filter[");
- dump("allowlist", mAllowlist, pw); pw.print(',');
- dump("denylist", mDenylist, pw); pw.print(']');
- }
-
- private void dump(String name, ArraySet<String> set, PrintWriter pw) {
- pw.print(name); pw.print("=(");
- final int n = set.size();
- for (int i = 0; i < n; i++) {
- if (i > 0) pw.print(',');
- pw.print(set.valueAt(i));
- }
- pw.print(')');
- }
-
- @Override
- public String toString() {
- StringWriter sw = new StringWriter();
- dump(new PrintWriter(sw, true));
- return sw.toString();
- }
-
- // value = comma-delimited list of tokens, where token = (package name|apps|*)
- // e.g. "com.package1", or "apps, com.android.keyguard" or "*"
- static Filter parse(String value) {
- if (value == null) return null;
- ArraySet<String> allowlist = new ArraySet<String>();
- ArraySet<String> denylist = new ArraySet<String>();
- for (String token : value.split(",")) {
- token = token.trim();
- if (token.startsWith("-") && token.length() > 1) {
- token = token.substring(1);
- denylist.add(token);
- } else {
- allowlist.add(token);
- }
- }
- return new Filter(allowlist, denylist);
- }
- }
-}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 71ecf725ab80..8b52b580a091 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -276,6 +276,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// Whether tasks have moved and we need to rank the tasks before next OOM scoring
private boolean mTaskLayersChanged = true;
private int mTmpTaskLayerRank;
+ private final ArraySet<WindowProcessController> mTmpTaskLayerChangedProcs = new ArraySet<>();
+ private final LockedScheduler mRankTaskLayersScheduler;
private boolean mTmpBoolean;
private RemoteException mTmpRemoteException;
@@ -450,6 +452,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
mStackSupervisor = mService.mStackSupervisor;
mStackSupervisor.mRootWindowContainer = this;
mDisplayOffTokenAcquirer = mService.new SleepTokenAcquirerImpl("Display-off");
+ mRankTaskLayersScheduler = new LockedScheduler(mService) {
+ @Override
+ public void execute() {
+ rankTaskLayersIfNeeded();
+ }
+ };
}
boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
@@ -2698,27 +2706,39 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
void invalidateTaskLayers() {
mTaskLayersChanged = true;
+ mRankTaskLayersScheduler.scheduleIfNeeded();
}
+ /** Generate oom-score-adjustment rank for all tasks in the system based on z-order. */
void rankTaskLayersIfNeeded() {
if (!mTaskLayersChanged) {
return;
}
mTaskLayersChanged = false;
mTmpTaskLayerRank = 0;
- final PooledConsumer c = PooledLambda.obtainConsumer(
- RootWindowContainer::rankTaskLayerForActivity, this,
- PooledLambda.__(ActivityRecord.class));
- forAllActivities(c);
- c.recycle();
- }
+ // Only rank for leaf tasks because the score of activity is based on immediate parent.
+ forAllLeafTasks(task -> {
+ final int oldRank = task.mLayerRank;
+ final ActivityRecord r = task.topRunningActivityLocked();
+ if (r != null && r.mVisibleRequested) {
+ task.mLayerRank = ++mTmpTaskLayerRank;
+ } else {
+ task.mLayerRank = Task.LAYER_RANK_INVISIBLE;
+ }
+ if (task.mLayerRank != oldRank) {
+ task.forAllActivities(activity -> {
+ if (activity.hasProcess()) {
+ mTmpTaskLayerChangedProcs.add(activity.app);
+ }
+ });
+ }
+ }, true /* traverseTopToBottom */);
- private void rankTaskLayerForActivity(ActivityRecord r) {
- if (r.canBeTopRunning() && r.mVisibleRequested) {
- r.getTask().mLayerRank = ++mTmpTaskLayerRank;
- } else {
- r.getTask().mLayerRank = -1;
+ for (int i = mTmpTaskLayerChangedProcs.size() - 1; i >= 0; i--) {
+ mTmpTaskLayerChangedProcs.valueAt(i).invalidateOomScoreReferenceState(
+ true /* computeNow */);
}
+ mTmpTaskLayerChangedProcs.clear();
}
void clearOtherAppTimeTrackers(AppTimeTracker except) {
@@ -3680,4 +3700,34 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
+ ", acquire at " + TimeUtils.formatUptime(mAcquireTime) + "}";
}
}
+
+ /**
+ * Helper class to schedule the runnable if it hasn't scheduled on display thread inside window
+ * manager lock.
+ */
+ abstract static class LockedScheduler implements Runnable {
+ private final ActivityTaskManagerService mService;
+ private boolean mScheduled;
+
+ LockedScheduler(ActivityTaskManagerService service) {
+ mService = service;
+ }
+
+ @Override
+ public void run() {
+ synchronized (mService.mGlobalLock) {
+ mScheduled = false;
+ execute();
+ }
+ }
+
+ abstract void execute();
+
+ void scheduleIfNeeded() {
+ if (!mScheduled) {
+ mService.mH.post(this);
+ mScheduled = true;
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 5f2113afa5b2..9ff99f5093d6 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -157,33 +157,33 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
}
@Override
- public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
+ public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
Rect outStableInsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
- return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
+ return mService.addWindow(this, window, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outDisplayCutout, outInputChannel,
outInsetsState, outActiveControls, UserHandle.getUserId(mUid));
}
@Override
- public int addToDisplayAsUser(IWindow window, int seq, WindowManager.LayoutParams attrs,
+ public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, int userId, Rect outFrame,
Rect outContentInsets, Rect outStableInsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
- return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
+ return mService.addWindow(this, window, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outDisplayCutout, outInputChannel,
outInsetsState, outActiveControls, userId);
}
@Override
- public int addToDisplayWithoutInputChannel(IWindow window, int seq, WindowManager.LayoutParams attrs,
+ public int addToDisplayWithoutInputChannel(IWindow window, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
InsetsState outInsetsState) {
- return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
+ return mService.addWindow(this, window, attrs, viewVisibility, displayId,
new Rect() /* outFrame */, outContentInsets, outStableInsets,
new DisplayCutout.ParcelableWrapper() /* cutout */, null /* outInputChannel */,
outInsetsState, mDummyControls, UserHandle.getUserId(mUid));
@@ -200,7 +200,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
}
@Override
- public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
+ public int relayout(IWindow window, WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
@@ -209,7 +209,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
+ Binder.getCallingPid());
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
- int res = mService.relayoutWindow(this, window, seq, attrs,
+ int res = mService.relayoutWindow(this, window, attrs,
requestedWidth, requestedHeight, viewFlags, flags, frameNumber,
outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,
outActiveControls, outSurfaceSize, outBLASTSurfaceControl);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index ce602de702d6..9be4ace60642 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -464,9 +464,10 @@ class Task extends WindowContainer<WindowContainer> {
int mMinWidth;
int mMinHeight;
+ static final int LAYER_RANK_INVISIBLE = -1;
// Ranking (from top) of this task among all visible tasks. (-1 means it's not visible)
// This number will be assigned when we evaluate OOM scores for all visible tasks.
- int mLayerRank = -1;
+ int mLayerRank = LAYER_RANK_INVISIBLE;
/** Helper object used for updating override configuration. */
private Configuration mTmpConfig = new Configuration();
@@ -1539,7 +1540,6 @@ class Task extends WindowContainer<WindowContainer> {
if (isPersistable) {
mLastTimeMoved = System.currentTimeMillis();
}
- mRootWindowContainer.invalidateTaskLayers();
}
// Close up recents linked list.
@@ -7452,6 +7452,10 @@ class Task extends WindowContainer<WindowContainer> {
if (!mChildren.contains(child)) {
return;
}
+ if (child.asTask() != null) {
+ // Non-root task position changed.
+ mRootWindowContainer.invalidateTaskLayers();
+ }
final boolean isTop = getTopChild() == child;
if (isTop) {
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 76bd6ce380e9..55e6a784d331 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -441,6 +441,12 @@ final class TaskDisplayArea extends DisplayArea<Task> {
}
@Override
+ void onChildPositionChanged(WindowContainer child) {
+ super.onChildPositionChanged(child);
+ mRootWindowContainer.invalidateTaskLayers();
+ }
+
+ @Override
boolean forAllTaskDisplayAreas(Function<TaskDisplayArea, Boolean> callback,
boolean traverseTopToBottom) {
return callback.apply(this);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index cccda3a4f4b8..6904740343a6 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -241,7 +241,7 @@ class TaskSnapshotSurface implements StartingSurface {
mergeInsetsSources(insetsState, topFullscreenOpaqueWindow.getRequestedInsetsState());
}
try {
- final int res = session.addToDisplay(window, window.mSeq, layoutParams,
+ final int res = session.addToDisplay(window, layoutParams,
View.GONE, activity.getDisplayContent().getDisplayId(), tmpFrames.frame,
tmpFrames.contentInsets, tmpFrames.stableInsets, tmpFrames.displayCutout,
null /* outInputChannel */, mTmpInsetsState, mTempControls);
@@ -258,7 +258,7 @@ class TaskSnapshotSurface implements StartingSurface {
insetsState);
window.setOuter(snapshotSurface);
try {
- session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1,
+ session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0, -1,
tmpFrames, tmpMergedConfiguration, surfaceControl, mTmpInsetsState,
mTempControls, sTmpSurfaceSize, sTmpSurfaceControl);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d9c574ccc64c..fa640367e1fe 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -411,7 +411,7 @@ public class WindowManagerService extends IWindowManager.Stub
* @see #DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY
*/
static boolean sDisableCustomTaskAnimationProperty =
- SystemProperties.getBoolean(DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY, false);
+ SystemProperties.getBoolean(DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY, true);
private static final String DISABLE_TRIPLE_BUFFERING_PROPERTY =
"ro.sf.disable_triple_buffer";
@@ -864,8 +864,7 @@ public class WindowManagerService extends IWindowManager.Stub
void updateSystemUiSettings() {
boolean changed;
synchronized (mGlobalLock) {
- changed = ImmersiveModeConfirmation.loadSetting(mCurrentUserId, mContext)
- || PolicyControl.reloadFromSetting(mContext);
+ changed = ImmersiveModeConfirmation.loadSetting(mCurrentUserId, mContext);
}
if (changed) {
updateRotation(false /* alwaysSendConfiguration */, false /* forceRelayout */);
@@ -1374,9 +1373,8 @@ public class WindowManagerService extends IWindowManager.Stub
return false;
}
- public int addWindow(Session session, IWindow client, int seq,
- LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
- Rect outContentInsets, Rect outStableInsets,
+ public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
+ int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState, InsetsSourceControl[] outActiveControls,
int requestUserId) {
@@ -1557,7 +1555,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
final WindowState win = new WindowState(this, session, client, token, parentWindow,
- appOp[0], seq, attrs, viewVisibility, session.mUid, userId,
+ appOp[0], attrs, viewVisibility, session.mUid, userId,
session.mCanAddInternalSystemWindow);
if (win.mDeathRecipient == null) {
// Client has apparently died, so there is no reason to
@@ -2099,7 +2097,7 @@ public class WindowManagerService extends IWindowManager.Stub
== PackageManager.PERMISSION_GRANTED;
}
- public int relayoutWindow(Session session, IWindow client, int seq, LayoutParams attrs,
+ public int relayoutWindow(Session session, IWindow client, LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewVisibility, int flags,
long frameNumber, ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
@@ -2141,17 +2139,15 @@ public class WindowManagerService extends IWindowManager.Stub
if (attrs != null) {
displayPolicy.adjustWindowParamsLw(win, attrs, pid, uid);
win.mToken.adjustWindowParams(win, attrs);
- // if they don't have the permission, mask out the status bar bits
- if (seq == win.mSeq) {
- int systemUiVisibility = attrs.systemUiVisibility
- | attrs.subtreeSystemUiVisibility;
- if ((systemUiVisibility & DISABLE_MASK) != 0) {
- if (!hasStatusBarPermission(pid, uid)) {
- systemUiVisibility &= ~DISABLE_MASK;
- }
+ int systemUiVisibility = attrs.systemUiVisibility
+ | attrs.subtreeSystemUiVisibility;
+ if ((systemUiVisibility & DISABLE_MASK) != 0) {
+ // if they don't have the permission, mask out the status bar bits
+ if (!hasStatusBarPermission(pid, uid)) {
+ systemUiVisibility &= ~DISABLE_MASK;
}
- win.mSystemUiVisibility = systemUiVisibility;
}
+ win.mSystemUiVisibility = systemUiVisibility;
if (win.mAttrs.type != attrs.type) {
throw new IllegalArgumentException(
"Window type can not be changed after the window is added.");
@@ -5731,31 +5727,13 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void statusBarVisibilityChanged(int displayId, int visibility) {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Caller does not hold permission "
- + android.Manifest.permission.STATUS_BAR);
- }
-
- synchronized (mGlobalLock) {
- final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
- if (displayContent != null) {
- displayContent.statusBarVisibilityChanged(visibility);
- } else {
- Slog.w(TAG, "statusBarVisibilityChanged with invalid displayId=" + displayId);
- }
- }
- }
-
- @Override
public void hideTransientBars(int displayId) {
mAtmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.STATUS_BAR,
"hideTransientBars()");
synchronized (mGlobalLock) {
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
if (displayContent != null) {
- displayContent.hideTransientBars();
+ displayContent.getInsetsPolicy().hideTransient();
} else {
Slog.w(TAG, "hideTransientBars with invalid displayId=" + displayId);
}
@@ -6112,7 +6090,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (inputMethodControlTarget != null) {
pw.print(" inputMethodControlTarget in display# "); pw.print(displayId);
- pw.print(' '); pw.println(inputMethodControlTarget.getWindow());
+ pw.print(' '); pw.println(inputMethodControlTarget);
}
});
pw.print(" mInTouchMode="); pw.println(mInTouchMode);
@@ -6164,7 +6142,6 @@ public class WindowManagerService extends IWindowManager.Stub
pw.print(" mRecentsAnimationController="); pw.println(mRecentsAnimationController);
mRecentsAnimationController.dump(pw, " ");
}
- PolicyControl.dump(" ", pw);
}
}
@@ -8270,4 +8247,14 @@ public class WindowManagerService extends IWindowManager.Stub
embeddedWindow.getName(), grantFocus);
}
}
+
+ @Override
+ public void holdLock(int durationMs) {
+ mContext.enforceCallingPermission(
+ Manifest.permission.INJECT_EVENTS, "holdLock requires shell identity");
+
+ synchronized (mGlobalLock) {
+ SystemClock.sleep(durationMs);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 268281b7a880..4b8a398582f3 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -221,6 +221,9 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
@Nullable
private BackgroundActivityStartCallback mBackgroundActivityStartCallback;
+ /** The state for oom-adjustment calculation. */
+ private final OomScoreReferenceState mOomRefState;
+
public WindowProcessController(@NonNull ActivityTaskManagerService atm, ApplicationInfo info,
String name, int uid, int userId, Object owner, WindowProcessListener listener) {
mInfo = info;
@@ -232,6 +235,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
mAtm = atm;
mDisplayId = INVALID_DISPLAY;
mBackgroundActivityStartCallback = mAtm.getBackgroundActivityStartCallback();
+ mOomRefState = new OomScoreReferenceState(this);
boolean isSysUiPackage = info.packageName.equals(
mAtm.getSysUiServiceComponentLocked().getPackageName());
@@ -688,15 +692,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
@HotPath(caller = HotPath.OOM_ADJUSTMENT)
public boolean hasVisibleActivities() {
- synchronized (mAtm.mGlobalLockWithoutBoost) {
- for (int i = mActivities.size() - 1; i >= 0; --i) {
- final ActivityRecord r = mActivities.get(i);
- if (r.mVisibleRequested) {
- return true;
- }
- }
- }
- return false;
+ return (mOomRefState.mActivityStateFlags & OomScoreReferenceState.FLAG_IS_VISIBLE) != 0;
}
@HotPath(caller = HotPath.LRU_UPDATE)
@@ -991,6 +987,34 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
mHostActivities.remove(r);
}
+ private static class OomScoreReferenceState extends RootWindowContainer.LockedScheduler {
+ private static final int FLAG_IS_VISIBLE = 0x10000000;
+ private static final int FLAG_IS_PAUSING = 0x20000000;
+ private static final int FLAG_IS_STOPPING = 0x40000000;
+ private static final int FLAG_IS_STOPPING_FINISHING = 0x80000000;
+ /** @see Task#mLayerRank */
+ private static final int MASK_MIN_TASK_LAYER = 0x0000ffff;
+
+ private final WindowProcessController mOwner;
+ boolean mChanged;
+
+ /**
+ * The higher 16 bits are the activity states, and the lower 16 bits are the task layer
+ * rank. This field is written by window manager and read by activity manager.
+ */
+ volatile int mActivityStateFlags = MASK_MIN_TASK_LAYER;
+
+ OomScoreReferenceState(WindowProcessController owner) {
+ super(owner.mAtm);
+ mOwner = owner;
+ }
+
+ @Override
+ public void execute() {
+ mOwner.computeOomScoreReferenceStateIfNeeded();
+ }
+ }
+
public interface ComputeOomAdjCallback {
void onVisibleActivity();
void onPausedActivity();
@@ -998,64 +1022,102 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
void onOtherActivity();
}
+ /**
+ * Returns the minimum task layer rank. It should only be called if {@link #hasActivities}
+ * returns {@code true}.
+ */
@HotPath(caller = HotPath.OOM_ADJUSTMENT)
- public int computeOomAdjFromActivities(int minTaskLayer, ComputeOomAdjCallback callback) {
+ public int computeOomAdjFromActivities(ComputeOomAdjCallback callback) {
+ final int flags = mOomRefState.mActivityStateFlags;
+ if ((flags & OomScoreReferenceState.FLAG_IS_VISIBLE) != 0) {
+ callback.onVisibleActivity();
+ } else if ((flags & OomScoreReferenceState.FLAG_IS_PAUSING) != 0) {
+ callback.onPausedActivity();
+ } else if ((flags & OomScoreReferenceState.FLAG_IS_STOPPING) != 0) {
+ callback.onStoppingActivity(
+ (flags & OomScoreReferenceState.FLAG_IS_STOPPING_FINISHING) != 0);
+ } else {
+ callback.onOtherActivity();
+ }
+ return flags & OomScoreReferenceState.MASK_MIN_TASK_LAYER;
+ }
+
+ void computeOomScoreReferenceStateIfNeeded() {
+ if (!mOomRefState.mChanged) {
+ return;
+ }
+ mOomRefState.mChanged = false;
+
// Since there could be more than one activities in a process record, we don't need to
// compute the OomAdj with each of them, just need to find out the activity with the
// "best" state, the order would be visible, pausing, stopping...
Task.ActivityState best = DESTROYED;
boolean finishing = true;
boolean visible = false;
- synchronized (mAtm.mGlobalLockWithoutBoost) {
- final int activitiesSize = mActivities.size();
- for (int j = 0; j < activitiesSize; j++) {
- final ActivityRecord r = mActivities.get(j);
- if (r.app != this) {
- Log.e(TAG, "Found activity " + r + " in proc activity list using " + r.app
- + " instead of expected " + this);
- if (r.app == null || (r.app.mUid == mUid)) {
- // Only fix things up when they look sane
- r.setProcess(this);
- } else {
- continue;
- }
- }
- if (r.mVisibleRequested) {
- final Task task = r.getTask();
- if (task != null && minTaskLayer > 0) {
- final int layer = task.mLayerRank;
- if (layer >= 0 && minTaskLayer > layer) {
- minTaskLayer = layer;
- }
- }
- visible = true;
- // continue the loop, in case there are multiple visible activities in
- // this process, we'd find out the one with the minimal layer, thus it'll
- // get a higher adj score.
+ int minTaskLayer = Integer.MAX_VALUE;
+ for (int i = mActivities.size() - 1; i >= 0; i--) {
+ final ActivityRecord r = mActivities.get(i);
+ if (r.app != this) {
+ Slog.e(TAG, "Found activity " + r + " in proc activity list using " + r.app
+ + " instead of expected " + this);
+ if (r.app == null || (r.app.mUid == mUid)) {
+ // Only fix things up when they look valid.
+ r.setProcess(this);
} else {
- if (best != PAUSING && best != PAUSED) {
- if (r.isState(PAUSING, PAUSED)) {
- best = PAUSING;
- } else if (r.isState(STOPPING)) {
- best = STOPPING;
- // Not "finishing" if any of activity isn't finishing.
- finishing &= r.finishing;
- }
+ continue;
+ }
+ }
+ if (r.mVisibleRequested) {
+ final Task task = r.getTask();
+ if (task != null && minTaskLayer > 0) {
+ final int layer = task.mLayerRank;
+ if (layer >= 0 && minTaskLayer > layer) {
+ minTaskLayer = layer;
}
}
+ visible = true;
+ // continue the loop, in case there are multiple visible activities in
+ // this process, we'd find out the one with the minimal layer, thus it'll
+ // get a higher adj score.
+ } else if (best != PAUSING && best != PAUSED) {
+ if (r.isState(PAUSING, PAUSED)) {
+ best = PAUSING;
+ } else if (r.isState(STOPPING)) {
+ best = STOPPING;
+ // Not "finishing" if any of activity isn't finishing.
+ finishing &= r.finishing;
+ }
+ }
+
+ int stateFlags = minTaskLayer & OomScoreReferenceState.MASK_MIN_TASK_LAYER;
+ if (visible) {
+ stateFlags |= OomScoreReferenceState.FLAG_IS_VISIBLE;
+ } else if (best == PAUSING) {
+ stateFlags |= OomScoreReferenceState.FLAG_IS_PAUSING;
+ } else if (best == STOPPING) {
+ stateFlags |= OomScoreReferenceState.FLAG_IS_STOPPING;
+ if (finishing) {
+ stateFlags |= OomScoreReferenceState.FLAG_IS_STOPPING_FINISHING;
+ }
}
+ mOomRefState.mActivityStateFlags = stateFlags;
}
- if (visible) {
- callback.onVisibleActivity();
- } else if (best == PAUSING) {
- callback.onPausedActivity();
- } else if (best == STOPPING) {
- callback.onStoppingActivity(finishing);
- } else {
- callback.onOtherActivity();
+ }
+
+ void invalidateOomScoreReferenceState(boolean computeNow) {
+ mOomRefState.mChanged = true;
+ if (computeNow) {
+ computeOomScoreReferenceStateIfNeeded();
+ return;
}
+ mOomRefState.scheduleIfNeeded();
+ }
- return minTaskLayer;
+ /** Called when the process has some oom related changes and it is going to update oom-adj. */
+ private void prepareOomAdjustment() {
+ mAtm.mRootWindowContainer.rankTaskLayersIfNeeded();
+ // The task layer may not change but the activity state in the same task may change.
+ computeOomScoreReferenceStateIfNeeded();
}
public int computeRelaunchReason() {
@@ -1097,6 +1159,9 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
if (addPendingTopUid) {
mAtm.mAmInternal.addPendingTopUid(mUid, mPid);
}
+ if (updateOomAdj) {
+ prepareOomAdjustment();
+ }
// Posting on handler so WM lock isn't held when we call into AM.
final Message m = PooledLambda.obtainMessage(WindowProcessListener::updateProcessInfo,
mListener, updateServiceConnectionActivities, activityChange, updateOomAdj);
@@ -1158,6 +1223,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
if (topProcessState == ActivityManager.PROCESS_STATE_TOP) {
mAtm.mAmInternal.addPendingTopUid(mUid, mPid);
}
+ prepareOomAdjustment();
// Posting the message at the front of queue so WM lock isn't held when we call into AM,
// and the process state of starting activity can be updated quicker which will give it a
// higher scheduling group.
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 1f7457c088c5..422e6f2d4ae0 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -302,7 +302,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
final boolean mIsImWindow;
final boolean mIsWallpaper;
private final boolean mIsFloatingLayer;
- int mSeq;
int mViewVisibility;
int mSystemUiVisibility;
@@ -834,10 +833,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
- WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
- int viewVisibility, int ownerId, int showUserId,
- boolean ownerCanAddInternalSystemWindow) {
- this(service, s, c, token, parentWindow, appOp, seq, a, viewVisibility, ownerId, showUserId,
+ WindowState parentWindow, int appOp, WindowManager.LayoutParams a, int viewVisibility,
+ int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow) {
+ this(service, s, c, token, parentWindow, appOp, a, viewVisibility, ownerId, showUserId,
ownerCanAddInternalSystemWindow, new PowerManagerWrapper() {
@Override
public void wakeUp(long time, @WakeReason int reason, String details) {
@@ -852,9 +850,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
- WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
- int viewVisibility, int ownerId, int showUserId,
- boolean ownerCanAddInternalSystemWindow, PowerManagerWrapper powerManagerWrapper) {
+ WindowState parentWindow, int appOp, WindowManager.LayoutParams a, int viewVisibility,
+ int ownerId, int showUserId, boolean ownerCanAddInternalSystemWindow,
+ PowerManagerWrapper powerManagerWrapper) {
super(service);
mSession = s;
mClient = c;
@@ -871,7 +869,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mPolicy = mWmService.mPolicy;
mContext = mWmService.mContext;
DeathRecipient deathRecipient = new DeathRecipient();
- mSeq = seq;
mPowerManagerWrapper = powerManagerWrapper;
mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
if (DEBUG) {
@@ -4031,7 +4028,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
pw.println(prefix + "mViewVisibility=0x" + Integer.toHexString(mViewVisibility)
+ " mHaveFrame=" + mHaveFrame
+ " mObscured=" + mObscured);
- pw.println(prefix + "mSeq=" + mSeq
+ pw.println(prefix
+ " mSystemUiVisibility=0x" + Integer.toHexString(mSystemUiVisibility));
}
if (!isVisibleByPolicy() || !mLegacyPolicyVisibilityAfterAnim || !mAppOpVisibility
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 17a05f3c7d1a..e39a3d1e9cb5 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -218,7 +218,7 @@ public:
void setFocusedApplication(JNIEnv* env, int32_t displayId, jobject applicationHandleObj);
void setFocusedDisplay(JNIEnv* env, int32_t displayId);
void setInputDispatchMode(bool enabled, bool frozen);
- void setSystemUiVisibility(int32_t visibility);
+ void setSystemUiLightsOut(bool lightsOut);
void setPointerSpeed(int32_t speed);
void setInputDeviceEnabled(uint32_t deviceId, bool enabled);
void setShowTouches(bool enabled);
@@ -286,8 +286,8 @@ private:
// Display size information.
std::vector<DisplayViewport> viewports;
- // System UI visibility.
- int32_t systemUiVisibility;
+ // True if System UI is less noticeable.
+ bool systemUiLightsOut;
// Pointer speed.
int32_t pointerSpeed;
@@ -339,7 +339,7 @@ NativeInputManager::NativeInputManager(jobject contextObj,
{
AutoMutex _l(mLock);
- mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
+ mLocked.systemUiLightsOut = false;
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = false;
@@ -366,8 +366,8 @@ void NativeInputManager::dump(std::string& dump) {
}
{
AutoMutex _l(mLock);
- dump += StringPrintf(INDENT "System UI Visibility: 0x%0" PRIx32 "\n",
- mLocked.systemUiVisibility);
+ dump += StringPrintf(INDENT "System UI Lights Out: %s\n",
+ toString(mLocked.systemUiLightsOut));
dump += StringPrintf(INDENT "Pointer Speed: %" PRId32 "\n", mLocked.pointerSpeed);
dump += StringPrintf(INDENT "Pointer Gestures Enabled: %s\n",
toString(mLocked.pointerGesturesEnabled));
@@ -811,11 +811,11 @@ void NativeInputManager::setInputDispatchMode(bool enabled, bool frozen) {
mInputManager->getDispatcher()->setInputDispatchMode(enabled, frozen);
}
-void NativeInputManager::setSystemUiVisibility(int32_t visibility) {
+void NativeInputManager::setSystemUiLightsOut(bool lightsOut) {
AutoMutex _l(mLock);
- if (mLocked.systemUiVisibility != visibility) {
- mLocked.systemUiVisibility = visibility;
+ if (mLocked.systemUiLightsOut != lightsOut) {
+ mLocked.systemUiLightsOut = lightsOut;
updateInactivityTimeoutLocked();
}
}
@@ -826,9 +826,8 @@ void NativeInputManager::updateInactivityTimeoutLocked() REQUIRES(mLock) {
return;
}
- bool lightsOut = mLocked.systemUiVisibility & ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN;
- controller->setInactivityTimeout(lightsOut ? InactivityTimeout::SHORT
- : InactivityTimeout::NORMAL);
+ controller->setInactivityTimeout(mLocked.systemUiLightsOut ? InactivityTimeout::SHORT
+ : InactivityTimeout::NORMAL);
}
void NativeInputManager::setPointerSpeed(int32_t speed) {
@@ -1578,11 +1577,11 @@ static void nativeSetInputDispatchMode(JNIEnv* /* env */,
im->setInputDispatchMode(enabled, frozen);
}
-static void nativeSetSystemUiVisibility(JNIEnv* /* env */,
- jclass /* clazz */, jlong ptr, jint visibility) {
+static void nativeSetSystemUiLightsOut(JNIEnv* /* env */, jclass /* clazz */, jlong ptr,
+ jboolean lightsOut) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
- im->setSystemUiVisibility(visibility);
+ im->setSystemUiLightsOut(lightsOut);
}
static jboolean nativeTransferTouchFocus(JNIEnv* env,
@@ -1802,7 +1801,7 @@ static const JNINativeMethod gInputManagerMethods[] = {
{"nativeSetFocusedDisplay", "(JI)V", (void*)nativeSetFocusedDisplay},
{"nativeSetPointerCapture", "(JZ)V", (void*)nativeSetPointerCapture},
{"nativeSetInputDispatchMode", "(JZZ)V", (void*)nativeSetInputDispatchMode},
- {"nativeSetSystemUiVisibility", "(JI)V", (void*)nativeSetSystemUiVisibility},
+ {"nativeSetSystemUiLightsOut", "(JZ)V", (void*)nativeSetSystemUiLightsOut},
{"nativeTransferTouchFocus", "(JLandroid/os/IBinder;Landroid/os/IBinder;)Z",
(void*)nativeTransferTouchFocus},
{"nativeSetPointerSpeed", "(JI)V", (void*)nativeSetPointerSpeed},
diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java
index 33317a38853e..8b1e9c52ec58 100644
--- a/services/people/java/com/android/server/people/PeopleService.java
+++ b/services/people/java/com/android/server/people/PeopleService.java
@@ -40,7 +40,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.server.SystemService;
import com.android.server.people.data.DataManager;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
@@ -95,28 +94,57 @@ public class PeopleService extends SystemService {
* @throws SecurityException if the caller is not system or root
*/
private static void enforceSystemOrRoot(String message) {
- int uid = Binder.getCallingUid();
- if (!UserHandle.isSameApp(uid, Process.SYSTEM_UID) && uid != Process.ROOT_UID) {
+ if (!isSystemOrRoot()) {
throw new SecurityException("Only system may " + message);
}
}
+ private static boolean isSystemOrRoot() {
+ final int uid = Binder.getCallingUid();
+ return UserHandle.isSameApp(uid, Process.SYSTEM_UID) || uid == Process.ROOT_UID;
+ }
+
+
+ /**
+ * Enforces that only the system, root UID or SystemUI can make certain calls.
+ *
+ * @param message used as message if SecurityException is thrown
+ * @throws SecurityException if the caller is not system or root
+ */
+ private static void enforceSystemRootOrSystemUI(Context context, String message) {
+ if (isSystemOrRoot()) return;
+ context.enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
+ message);
+ }
+
private final class BinderService extends IPeopleManager.Stub {
@Override
public ParceledListSlice<ConversationChannel> getRecentConversations() {
enforceSystemOrRoot("get recent conversations");
- return new ParceledListSlice<>(new ArrayList<>());
+ return new ParceledListSlice<>(
+ mDataManager.getRecentConversations(
+ Binder.getCallingUserHandle().getIdentifier()));
}
@Override
public void removeRecentConversation(String packageName, int userId, String shortcutId) {
enforceSystemOrRoot("remove a recent conversation");
+ mDataManager.removeRecentConversation(packageName, userId, shortcutId,
+ Binder.getCallingUserHandle().getIdentifier());
}
@Override
public void removeAllRecentConversations() {
enforceSystemOrRoot("remove all recent conversations");
+ mDataManager.removeAllRecentConversations(
+ Binder.getCallingUserHandle().getIdentifier());
+ }
+
+ @Override
+ public long getLastInteraction(String packageName, int userId, String shortcutId) {
+ enforceSystemRootOrSystemUI(getContext(), "get last interaction");
+ return mDataManager.getLastInteraction(packageName, userId, shortcutId);
}
}
diff --git a/services/people/java/com/android/server/people/data/ConversationInfo.java b/services/people/java/com/android/server/people/data/ConversationInfo.java
index 17378285276f..45f389cbd3ff 100644
--- a/services/people/java/com/android/server/people/data/ConversationInfo.java
+++ b/services/people/java/com/android/server/people/data/ConversationInfo.java
@@ -90,6 +90,11 @@ public class ConversationInfo {
@Nullable
private String mNotificationChannelId;
+ @Nullable
+ private String mParentNotificationChannelId;
+
+ private long mLastEventTimestamp;
+
@ShortcutFlags
private int mShortcutFlags;
@@ -102,6 +107,8 @@ public class ConversationInfo {
mContactUri = builder.mContactUri;
mContactPhoneNumber = builder.mContactPhoneNumber;
mNotificationChannelId = builder.mNotificationChannelId;
+ mParentNotificationChannelId = builder.mParentNotificationChannelId;
+ mLastEventTimestamp = builder.mLastEventTimestamp;
mShortcutFlags = builder.mShortcutFlags;
mConversationFlags = builder.mConversationFlags;
}
@@ -129,14 +136,32 @@ public class ConversationInfo {
}
/**
- * ID of the {@link android.app.NotificationChannel} where the notifications for this
- * conversation are posted.
+ * ID of the conversation-specific {@link android.app.NotificationChannel} where the
+ * notifications for this conversation are posted.
*/
@Nullable
String getNotificationChannelId() {
return mNotificationChannelId;
}
+ /**
+ * ID of the parent {@link android.app.NotificationChannel} for this conversation. This is the
+ * notification channel where the notifications are posted before this conversation is
+ * customized by the user.
+ */
+ @Nullable
+ String getParentNotificationChannelId() {
+ return mParentNotificationChannelId;
+ }
+
+ /**
+ * Timestamp of the last event, {@code 0L} if there are no events. This timestamp is for
+ * identifying and sorting the recent conversations. It may only count a subset of event types.
+ */
+ long getLastEventTimestamp() {
+ return mLastEventTimestamp;
+ }
+
/** Whether the shortcut for this conversation is set long-lived by the app. */
public boolean isShortcutLongLived() {
return hasShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED);
@@ -202,6 +227,8 @@ public class ConversationInfo {
&& Objects.equals(mContactUri, other.mContactUri)
&& Objects.equals(mContactPhoneNumber, other.mContactPhoneNumber)
&& Objects.equals(mNotificationChannelId, other.mNotificationChannelId)
+ && Objects.equals(mParentNotificationChannelId, other.mParentNotificationChannelId)
+ && Objects.equals(mLastEventTimestamp, other.mLastEventTimestamp)
&& mShortcutFlags == other.mShortcutFlags
&& mConversationFlags == other.mConversationFlags;
}
@@ -209,7 +236,8 @@ public class ConversationInfo {
@Override
public int hashCode() {
return Objects.hash(mShortcutId, mLocusId, mContactUri, mContactPhoneNumber,
- mNotificationChannelId, mShortcutFlags, mConversationFlags);
+ mNotificationChannelId, mParentNotificationChannelId, mLastEventTimestamp,
+ mShortcutFlags, mConversationFlags);
}
@Override
@@ -221,6 +249,8 @@ public class ConversationInfo {
sb.append(", contactUri=").append(mContactUri);
sb.append(", phoneNumber=").append(mContactPhoneNumber);
sb.append(", notificationChannelId=").append(mNotificationChannelId);
+ sb.append(", parentNotificationChannelId=").append(mParentNotificationChannelId);
+ sb.append(", lastEventTimestamp=").append(mLastEventTimestamp);
sb.append(", shortcutFlags=0x").append(Integer.toHexString(mShortcutFlags));
sb.append(" [");
if (isShortcutLongLived()) {
@@ -280,6 +310,11 @@ public class ConversationInfo {
protoOutputStream.write(ConversationInfoProto.NOTIFICATION_CHANNEL_ID,
mNotificationChannelId);
}
+ if (mParentNotificationChannelId != null) {
+ protoOutputStream.write(ConversationInfoProto.PARENT_NOTIFICATION_CHANNEL_ID,
+ mParentNotificationChannelId);
+ }
+ protoOutputStream.write(ConversationInfoProto.LAST_EVENT_TIMESTAMP, mLastEventTimestamp);
protoOutputStream.write(ConversationInfoProto.SHORTCUT_FLAGS, mShortcutFlags);
protoOutputStream.write(ConversationInfoProto.CONVERSATION_FLAGS, mConversationFlags);
if (mContactPhoneNumber != null) {
@@ -300,6 +335,8 @@ public class ConversationInfo {
out.writeInt(mShortcutFlags);
out.writeInt(mConversationFlags);
out.writeUTF(mContactPhoneNumber != null ? mContactPhoneNumber : "");
+ out.writeUTF(mParentNotificationChannelId != null ? mParentNotificationChannelId : "");
+ out.writeLong(mLastEventTimestamp);
} catch (IOException e) {
Slog.e(TAG, "Failed to write fields to backup payload.", e);
return null;
@@ -338,6 +375,14 @@ public class ConversationInfo {
builder.setNotificationChannelId(protoInputStream.readString(
ConversationInfoProto.NOTIFICATION_CHANNEL_ID));
break;
+ case (int) ConversationInfoProto.PARENT_NOTIFICATION_CHANNEL_ID:
+ builder.setParentNotificationChannelId(protoInputStream.readString(
+ ConversationInfoProto.PARENT_NOTIFICATION_CHANNEL_ID));
+ break;
+ case (int) ConversationInfoProto.LAST_EVENT_TIMESTAMP:
+ builder.setLastEventTimestamp(protoInputStream.readLong(
+ ConversationInfoProto.LAST_EVENT_TIMESTAMP));
+ break;
case (int) ConversationInfoProto.SHORTCUT_FLAGS:
builder.setShortcutFlags(protoInputStream.readInt(
ConversationInfoProto.SHORTCUT_FLAGS));
@@ -382,6 +427,11 @@ public class ConversationInfo {
if (!TextUtils.isEmpty(contactPhoneNumber)) {
builder.setContactPhoneNumber(contactPhoneNumber);
}
+ String parentNotificationChannelId = in.readUTF();
+ if (!TextUtils.isEmpty(parentNotificationChannelId)) {
+ builder.setParentNotificationChannelId(parentNotificationChannelId);
+ }
+ builder.setLastEventTimestamp(in.readLong());
} catch (IOException e) {
Slog.e(TAG, "Failed to read conversation info fields from backup payload.", e);
return null;
@@ -408,6 +458,11 @@ public class ConversationInfo {
@Nullable
private String mNotificationChannelId;
+ @Nullable
+ private String mParentNotificationChannelId;
+
+ private long mLastEventTimestamp;
+
@ShortcutFlags
private int mShortcutFlags;
@@ -427,6 +482,8 @@ public class ConversationInfo {
mContactUri = conversationInfo.mContactUri;
mContactPhoneNumber = conversationInfo.mContactPhoneNumber;
mNotificationChannelId = conversationInfo.mNotificationChannelId;
+ mParentNotificationChannelId = conversationInfo.mParentNotificationChannelId;
+ mLastEventTimestamp = conversationInfo.mLastEventTimestamp;
mShortcutFlags = conversationInfo.mShortcutFlags;
mConversationFlags = conversationInfo.mConversationFlags;
}
@@ -456,6 +513,16 @@ public class ConversationInfo {
return this;
}
+ Builder setParentNotificationChannelId(String parentNotificationChannelId) {
+ mParentNotificationChannelId = parentNotificationChannelId;
+ return this;
+ }
+
+ Builder setLastEventTimestamp(long lastEventTimestamp) {
+ mLastEventTimestamp = lastEventTimestamp;
+ return this;
+ }
+
Builder setShortcutFlags(@ShortcutFlags int shortcutFlags) {
mShortcutFlags = shortcutFlags;
return this;
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 52fec339e331..87f2c581ef8f 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -24,6 +24,7 @@ import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Person;
+import android.app.people.ConversationChannel;
import android.app.prediction.AppTarget;
import android.app.prediction.AppTargetEvent;
import android.app.usage.UsageEvents;
@@ -74,9 +75,11 @@ import com.android.server.notification.ShortcutHelper;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.PriorityQueue;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@@ -97,6 +100,7 @@ public class DataManager {
private static final long QUERY_EVENTS_MAX_AGE_MS = 5L * DateUtils.MINUTE_IN_MILLIS;
private static final long USAGE_STATS_QUERY_INTERVAL_SEC = 120L;
+ @VisibleForTesting static final int MAX_CACHED_RECENT_SHORTCUTS = 30;
private final Context mContext;
private final Injector mInjector;
@@ -209,6 +213,83 @@ public class DataManager {
mContext.getPackageName(), intentFilter, callingUserId);
}
+ /** Returns the cached non-customized recent conversations. */
+ public List<ConversationChannel> getRecentConversations(@UserIdInt int callingUserId) {
+ List<ConversationChannel> conversationChannels = new ArrayList<>();
+ forPackagesInProfile(callingUserId, packageData -> {
+ String packageName = packageData.getPackageName();
+ int userId = packageData.getUserId();
+ packageData.forAllConversations(conversationInfo -> {
+ if (!isCachedRecentConversation(conversationInfo)) {
+ return;
+ }
+ String shortcutId = conversationInfo.getShortcutId();
+ ShortcutInfo shortcutInfo = getShortcut(packageName, userId, shortcutId);
+ int uid = mPackageManagerInternal.getPackageUid(packageName, 0, userId);
+ NotificationChannel parentChannel =
+ mNotificationManagerInternal.getNotificationChannel(packageName, uid,
+ conversationInfo.getParentNotificationChannelId());
+ if (shortcutInfo == null || parentChannel == null) {
+ return;
+ }
+ conversationChannels.add(
+ new ConversationChannel(shortcutInfo, parentChannel,
+ conversationInfo.getLastEventTimestamp(),
+ hasActiveNotifications(packageName, userId, shortcutId)));
+ });
+ });
+ return conversationChannels;
+ }
+
+ /**
+ * Uncaches the shortcut that's associated with the specified conversation so this conversation
+ * will not show up in the recent conversations list.
+ */
+ public void removeRecentConversation(String packageName, int userId, String shortcutId,
+ @UserIdInt int callingUserId) {
+ if (!hasActiveNotifications(packageName, userId, shortcutId)) {
+ mShortcutServiceInternal.uncacheShortcuts(callingUserId, mContext.getPackageName(),
+ packageName, Collections.singletonList(shortcutId), userId,
+ ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+ }
+ }
+
+ /**
+ * Uncaches the shortcuts for all the recent conversations that they don't have active
+ * notifications.
+ */
+ public void removeAllRecentConversations(@UserIdInt int callingUserId) {
+ forPackagesInProfile(callingUserId, packageData -> {
+ String packageName = packageData.getPackageName();
+ int userId = packageData.getUserId();
+ List<String> idsToUncache = new ArrayList<>();
+ packageData.forAllConversations(conversationInfo -> {
+ String shortcutId = conversationInfo.getShortcutId();
+ if (isCachedRecentConversation(conversationInfo)
+ && !hasActiveNotifications(packageName, userId, shortcutId)) {
+ idsToUncache.add(shortcutId);
+ }
+ });
+ mShortcutServiceInternal.uncacheShortcuts(callingUserId, mContext.getPackageName(),
+ packageName, idsToUncache, userId, ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+ });
+ }
+
+ /**
+ * Returns the last notification interaction with the specified conversation. If the
+ * conversation can't be found or no interactions have been recorded, returns 0L.
+ */
+ public long getLastInteraction(String packageName, int userId, String shortcutId) {
+ final PackageData packageData = getPackage(packageName, userId);
+ if (packageData != null) {
+ final ConversationInfo conversationInfo = packageData.getConversationInfo(shortcutId);
+ if (conversationInfo != null) {
+ return conversationInfo.getLastEventTimestamp();
+ }
+ }
+ return 0L;
+ }
+
/** Reports the sharing related {@link AppTargetEvent} from App Prediction Manager. */
public void reportShareTargetEvent(@NonNull AppTargetEvent event,
@NonNull IntentFilter intentFilter) {
@@ -278,7 +359,6 @@ public class DataManager {
}
pruneUninstalledPackageData(userData);
- final NotificationListener notificationListener = mNotificationListeners.get(userId);
userData.forAllPackages(packageData -> {
if (signal.isCanceled()) {
return;
@@ -291,20 +371,7 @@ public class DataManager {
packageData.getEventStore().deleteEventHistories(EventStore.CATEGORY_SMS);
}
packageData.pruneOrphanEvents();
- if (notificationListener != null) {
- String packageName = packageData.getPackageName();
- packageData.forAllConversations(conversationInfo -> {
- if (conversationInfo.isShortcutCachedForNotification()
- && conversationInfo.getNotificationChannelId() == null
- && !notificationListener.hasActiveNotifications(
- packageName, conversationInfo.getShortcutId())) {
- mShortcutServiceInternal.uncacheShortcuts(userId,
- mContext.getPackageName(), packageName,
- Collections.singletonList(conversationInfo.getShortcutId()),
- userId, ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
- }
- });
- }
+ cleanupCachedShortcuts(userId, MAX_CACHED_RECENT_SHORTCUTS);
});
}
@@ -467,7 +534,8 @@ public class DataManager {
@NonNull String packageName, @UserIdInt int userId,
@Nullable List<String> shortcutIds) {
@ShortcutQuery.QueryFlags int queryFlags = ShortcutQuery.FLAG_MATCH_DYNAMIC
- | ShortcutQuery.FLAG_MATCH_PINNED | ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER;
+ | ShortcutQuery.FLAG_MATCH_PINNED | ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER
+ | ShortcutQuery.FLAG_MATCH_CACHED;
return mShortcutServiceInternal.getShortcuts(
UserHandle.USER_SYSTEM, mContext.getPackageName(),
/*changedSince=*/ 0, packageName, shortcutIds, /*locusIds=*/ null,
@@ -527,6 +595,68 @@ public class DataManager {
return packageData;
}
+ private boolean isCachedRecentConversation(ConversationInfo conversationInfo) {
+ return conversationInfo.isShortcutCachedForNotification()
+ && conversationInfo.getNotificationChannelId() == null
+ && conversationInfo.getParentNotificationChannelId() != null
+ && conversationInfo.getLastEventTimestamp() > 0L;
+ }
+
+ private boolean hasActiveNotifications(String packageName, @UserIdInt int userId,
+ String shortcutId) {
+ NotificationListener notificationListener = mNotificationListeners.get(userId);
+ return notificationListener != null
+ && notificationListener.hasActiveNotifications(packageName, shortcutId);
+ }
+
+ /**
+ * Cleans up the oldest cached shortcuts that don't have active notifications for the recent
+ * conversations. After the cleanup, normally, the total number of cached shortcuts will be
+ * less than or equal to the target count. However, there are exception cases: e.g. when all
+ * the existing cached shortcuts have active notifications.
+ */
+ private void cleanupCachedShortcuts(@UserIdInt int userId, int targetCachedCount) {
+ UserData userData = getUnlockedUserData(userId);
+ if (userData == null) {
+ return;
+ }
+ // pair of <package name, conversation info>
+ List<Pair<String, ConversationInfo>> cachedConvos = new ArrayList<>();
+ userData.forAllPackages(packageData ->
+ packageData.forAllConversations(conversationInfo -> {
+ if (isCachedRecentConversation(conversationInfo)) {
+ cachedConvos.add(
+ Pair.create(packageData.getPackageName(), conversationInfo));
+ }
+ })
+ );
+ if (cachedConvos.size() <= targetCachedCount) {
+ return;
+ }
+ int numToUncache = cachedConvos.size() - targetCachedCount;
+ // Max heap keeps the oldest cached conversations.
+ PriorityQueue<Pair<String, ConversationInfo>> maxHeap = new PriorityQueue<>(
+ numToUncache + 1,
+ Comparator.comparingLong((Pair<String, ConversationInfo> pair) ->
+ pair.second.getLastEventTimestamp()).reversed());
+ for (Pair<String, ConversationInfo> cached : cachedConvos) {
+ if (hasActiveNotifications(cached.first, userId, cached.second.getShortcutId())) {
+ continue;
+ }
+ maxHeap.offer(cached);
+ if (maxHeap.size() > numToUncache) {
+ maxHeap.poll();
+ }
+ }
+ while (!maxHeap.isEmpty()) {
+ Pair<String, ConversationInfo> toUncache = maxHeap.poll();
+ mShortcutServiceInternal.uncacheShortcuts(userId,
+ mContext.getPackageName(), toUncache.first,
+ Collections.singletonList(toUncache.second.getShortcutId()),
+ userId, ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+ }
+ }
+
@VisibleForTesting
@WorkerThread
void addOrUpdateConversationInfo(@NonNull ShortcutInfo shortcutInfo) {
@@ -737,9 +867,21 @@ public class DataManager {
public void onShortcutsAddedOrUpdated(@NonNull String packageName,
@NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
mInjector.getBackgroundExecutor().execute(() -> {
+ PackageData packageData = getPackage(packageName, user.getIdentifier());
for (ShortcutInfo shortcut : shortcuts) {
if (ShortcutHelper.isConversationShortcut(
shortcut, mShortcutServiceInternal, user.getIdentifier())) {
+ if (shortcut.isCached()) {
+ ConversationInfo conversationInfo = packageData != null
+ ? packageData.getConversationInfo(shortcut.getId()) : null;
+ if (conversationInfo == null
+ || !conversationInfo.isShortcutCachedForNotification()) {
+ // This is a newly cached shortcut. Clean up the existing cached
+ // shortcuts to ensure the cache size is under the limit.
+ cleanupCachedShortcuts(user.getIdentifier(),
+ MAX_CACHED_RECENT_SHORTCUTS - 1);
+ }
+ }
addOrUpdateConversationInfo(shortcut);
}
}
@@ -800,6 +942,16 @@ public class DataManager {
});
if (packageData != null) {
+ ConversationInfo conversationInfo = packageData.getConversationInfo(shortcutId);
+ if (conversationInfo == null) {
+ return;
+ }
+ ConversationInfo updated = new ConversationInfo.Builder(conversationInfo)
+ .setLastEventTimestamp(sbn.getPostTime())
+ .setParentNotificationChannelId(sbn.getNotification().getChannelId())
+ .build();
+ packageData.getConversationStore().addOrUpdate(updated);
+
EventHistoryImpl eventHistory = packageData.getEventStore().getOrCreateEventHistory(
EventStore.CATEGORY_SHORTCUT_BASED, shortcutId);
eventHistory.addEvent(new Event(sbn.getPostTime(), Event.TYPE_NOTIFICATION_POSTED));
@@ -820,16 +972,7 @@ public class DataManager {
int count = mActiveNotifCounts.getOrDefault(conversationKey, 0) - 1;
if (count <= 0) {
mActiveNotifCounts.remove(conversationKey);
- // The shortcut was cached by Notification Manager synchronously when the
- // associated notification was posted. Uncache it here when all the
- // associated notifications are removed.
- if (conversationInfo.isShortcutCachedForNotification()
- && conversationInfo.getNotificationChannelId() == null) {
- mShortcutServiceInternal.uncacheShortcuts(mUserId,
- mContext.getPackageName(), sbn.getPackageName(),
- Collections.singletonList(conversationInfo.getShortcutId()),
- mUserId, ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
- }
+ cleanupCachedShortcuts(mUserId, MAX_CACHED_RECENT_SHORTCUTS);
} else {
mActiveNotifCounts.put(conversationKey, count);
}
@@ -885,24 +1028,6 @@ public class DataManager {
conversationStore.addOrUpdate(builder.build());
}
- synchronized void cleanupCachedShortcuts() {
- for (Pair<String, String> conversationKey : mActiveNotifCounts.keySet()) {
- String packageName = conversationKey.first;
- String shortcutId = conversationKey.second;
- PackageData packageData = getPackage(packageName, mUserId);
- ConversationInfo conversationInfo =
- packageData != null ? packageData.getConversationInfo(shortcutId) : null;
- if (conversationInfo != null
- && conversationInfo.isShortcutCachedForNotification()
- && conversationInfo.getNotificationChannelId() == null) {
- mShortcutServiceInternal.uncacheShortcuts(mUserId,
- mContext.getPackageName(), packageName,
- Collections.singletonList(shortcutId),
- mUserId, ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
- }
- }
- }
-
synchronized boolean hasActiveNotifications(String packageName, String shortcutId) {
return mActiveNotifCounts.containsKey(Pair.create(packageName, shortcutId));
}
@@ -975,16 +1100,7 @@ public class DataManager {
@Override
public void onReceive(Context context, Intent intent) {
- forAllUnlockedUsers(userData -> {
- NotificationListener listener = mNotificationListeners.get(userData.getUserId());
- // Clean up the cached shortcuts because all the notifications are cleared after
- // system shutdown. The associated shortcuts need to be uncached to keep in sync
- // unless the settings are changed by the user.
- if (listener != null) {
- listener.cleanupCachedShortcuts();
- }
- userData.forAllPackages(PackageData::saveToDisk);
- });
+ forAllUnlockedUsers(userData -> userData.forAllPackages(PackageData::saveToDisk));
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 5d8f662301c1..a250c217614d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -351,7 +351,7 @@ public class MockingOomAdjusterTests {
doReturn(mock(WindowProcessController.class)).when(app).getWindowProcessController();
WindowProcessController wpc = app.getWindowProcessController();
doReturn(true).when(wpc).hasActivities();
- doAnswer(answer((minTaskLayer, callback) -> {
+ doAnswer(answer(callback -> {
Field field = callback.getClass().getDeclaredField("adj");
field.set(callback, VISIBLE_APP_ADJ);
field = callback.getClass().getDeclaredField("foregroundActivities");
@@ -361,7 +361,7 @@ public class MockingOomAdjusterTests {
field = callback.getClass().getDeclaredField("schedGroup");
field.set(callback, SCHED_GROUP_TOP_APP);
return 0;
- })).when(wpc).computeOomAdjFromActivities(anyInt(),
+ })).when(wpc).computeOomAdjFromActivities(
any(WindowProcessController.ComputeOomAdjCallback.class));
sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 90e1cfcd305a..79936ce6d623 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -77,6 +77,7 @@
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
<uses-permission android:name="android.permission.DUMP"/>
<uses-permission android:name="android.permission.READ_DREAM_STATE"/>
+ <uses-permission android:name="android.permission.READ_DREAM_SUPPRESSION"/>
<uses-permission android:name="android.permission.WRITE_DREAM_STATE"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
index 08f558e6d99c..1385376b740d 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java
@@ -54,8 +54,6 @@ public class ArcInitiationActionFromAvrTest {
private Context mContextSpy;
private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem;
- private HdmiCecController mHdmiCecController;
- private HdmiControlService mHdmiControlService;
private FakeNativeWrapper mNativeWrapper;
private ArcInitiationActionFromAvr mAction;
@@ -78,7 +76,7 @@ public class ArcInitiationActionFromAvrTest {
when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
- mHdmiControlService =
+ HdmiControlService hdmiControlService =
new HdmiControlService(mContextSpy) {
@Override
boolean isPowerStandby() {
@@ -110,7 +108,7 @@ public class ArcInitiationActionFromAvrTest {
}
};
- mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(mHdmiControlService) {
+ mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(hdmiControlService) {
@Override
protected void setPreferredAddress(int addr) {
}
@@ -118,18 +116,18 @@ public class ArcInitiationActionFromAvrTest {
mHdmiCecLocalDeviceAudioSystem.init();
Looper looper = mTestLooper.getLooper();
- mHdmiControlService.setIoLooper(looper);
+ hdmiControlService.setIoLooper(looper);
mNativeWrapper = new FakeNativeWrapper();
- mHdmiCecController = HdmiCecController.createWithNativeWrapper(
- this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
- mHdmiControlService.setCecController(mHdmiCecController);
- mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
- mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
- mHdmiControlService.initPortInfo();
+ HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
+ hdmiControlService, mNativeWrapper, hdmiControlService.getAtomWriter());
+ hdmiControlService.setCecController(hdmiCecController);
+ hdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(hdmiControlService));
+ hdmiControlService.setMessageValidator(new HdmiCecMessageValidator(hdmiControlService));
+ hdmiControlService.initPortInfo();
mAction = new ArcInitiationActionFromAvr(mHdmiCecLocalDeviceAudioSystem);
mLocalDevices.add(mHdmiCecLocalDeviceAudioSystem);
- mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ hdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
mTestLooper.dispatchAll();
}
@@ -142,7 +140,7 @@ public class ArcInitiationActionFromAvrTest {
assertThat(mNativeWrapper.getResultMessages()).contains(initiateArc);
- mHdmiControlService.sendCecCommand(
+ mNativeWrapper.onCecMessage(
HdmiCecMessageBuilder.buildReportArcInitiated(
Constants.ADDR_TV,
Constants.ADDR_AUDIO_SYSTEM));
@@ -174,7 +172,7 @@ public class ArcInitiationActionFromAvrTest {
assertThat(mNativeWrapper.getResultMessages()).contains(initiateArc);
- mHdmiControlService.handleCecCommand(HdmiCecMessageBuilder.buildReportArcTerminated(
+ mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildReportArcTerminated(
Constants.ADDR_TV,
Constants.ADDR_AUDIO_SYSTEM));
mTestLooper.dispatchAll();
@@ -192,7 +190,7 @@ public class ArcInitiationActionFromAvrTest {
assertThat(mNativeWrapper.getResultMessages()).contains(initiateArc);
- mHdmiControlService.handleCecCommand(
+ mNativeWrapper.onCecMessage(
HdmiCecMessageBuilder.buildFeatureAbortCommand(
Constants.ADDR_TV,
Constants.ADDR_AUDIO_SYSTEM, Constants.MESSAGE_INITIATE_ARC,
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
index 4afbbf741102..169f885a7253 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
@@ -56,8 +56,6 @@ public class ArcTerminationActionFromAvrTest {
private HdmiCecLocalDeviceAudioSystem mHdmiCecLocalDeviceAudioSystem;
private ArcTerminationActionFromAvr mAction;
- private HdmiCecController mHdmiCecController;
- private HdmiControlService mHdmiControlService;
private FakeNativeWrapper mNativeWrapper;
private TestLooper mTestLooper = new TestLooper();
@@ -79,7 +77,7 @@ public class ArcTerminationActionFromAvrTest {
when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
when(mIPowerManagerMock.isInteractive()).thenReturn(true);
- mHdmiControlService =
+ HdmiControlService hdmiControlService =
new HdmiControlService(mContextSpy) {
@Override
void wakeUp() {
@@ -112,16 +110,16 @@ public class ArcTerminationActionFromAvrTest {
};
Looper looper = mTestLooper.getLooper();
- mHdmiControlService.setIoLooper(looper);
+ hdmiControlService.setIoLooper(looper);
mNativeWrapper = new FakeNativeWrapper();
- mHdmiCecController = HdmiCecController.createWithNativeWrapper(
- this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
- mHdmiControlService.setCecController(mHdmiCecController);
- mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService));
- mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService));
- mHdmiControlService.initPortInfo();
-
- mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(mHdmiControlService) {
+ HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper(
+ hdmiControlService, mNativeWrapper, hdmiControlService.getAtomWriter());
+ hdmiControlService.setCecController(hdmiCecController);
+ hdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(hdmiControlService));
+ hdmiControlService.setMessageValidator(new HdmiCecMessageValidator(hdmiControlService));
+ hdmiControlService.initPortInfo();
+
+ mHdmiCecLocalDeviceAudioSystem = new HdmiCecLocalDeviceAudioSystem(hdmiControlService) {
@Override
protected void setPreferredAddress(int addr) {
}
@@ -130,7 +128,7 @@ public class ArcTerminationActionFromAvrTest {
mAction = new ArcTerminationActionFromAvr(mHdmiCecLocalDeviceAudioSystem);
mLocalDevices.add(mHdmiCecLocalDeviceAudioSystem);
- mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ hdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
mHdmiCecLocalDeviceAudioSystem.setArcStatus(true);
mTestLooper.dispatchAll();
}
@@ -173,7 +171,7 @@ public class ArcTerminationActionFromAvrTest {
HdmiCecMessage arcTerminatedResponse = HdmiCecMessageBuilder.buildReportArcTerminated(
Constants.ADDR_TV, Constants.ADDR_AUDIO_SYSTEM);
- mHdmiControlService.handleCecCommand(arcTerminatedResponse);
+ mNativeWrapper.onCecMessage(arcTerminatedResponse);
mTestLooper.dispatchAll();
assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isFalse();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
index 01f0a3d398df..2c42791fabce 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java
@@ -16,7 +16,11 @@
package com.android.server.hdmi;
import android.hardware.hdmi.HdmiPortInfo;
+import android.hardware.tv.cec.V1_0.CecMessage;
+import android.hardware.tv.cec.V1_0.HotplugEvent;
import android.hardware.tv.cec.V1_0.SendMessageResult;
+import android.os.RemoteException;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.hdmi.HdmiCecController.NativeWrapper;
@@ -29,6 +33,8 @@ import java.util.List;
/** Fake {@link NativeWrapper} useful for testing. */
final class FakeNativeWrapper implements NativeWrapper {
+ private static final String TAG = "FakeNativeWrapper";
+
private final int[] mPollAddressResponse =
new int[] {
SendMessageResult.NACK,
@@ -52,6 +58,7 @@ final class FakeNativeWrapper implements NativeWrapper {
private final HashMap<Integer, Integer> mMessageSendResult = new HashMap<>();
private int mMyPhysicalAddress = 0;
private HdmiPortInfo[] mHdmiPortInfo = null;
+ private HdmiCecController.HdmiCecCallback mCallback = null;
@Override
public String nativeInit() {
@@ -59,7 +66,9 @@ final class FakeNativeWrapper implements NativeWrapper {
}
@Override
- public void setCallback(HdmiCecController.HdmiCecCallback callback) {}
+ public void setCallback(HdmiCecController.HdmiCecCallback callback) {
+ this.mCallback = callback;
+ }
@Override
public int nativeSendCecCommand(
@@ -119,6 +128,42 @@ final class FakeNativeWrapper implements NativeWrapper {
return false;
}
+ public void onCecMessage(HdmiCecMessage hdmiCecMessage) {
+ if (mCallback == null) {
+ return;
+ }
+ CecMessage message = new CecMessage();
+ message.initiator = hdmiCecMessage.getSource();
+ message.destination = hdmiCecMessage.getDestination();
+ ArrayList<Byte> body = new ArrayList<>();
+ body.add((byte) hdmiCecMessage.getOpcode());
+ for (byte param : hdmiCecMessage.getParams()) {
+ body.add(param);
+ }
+ message.body = body;
+ try {
+ mCallback.onCecMessage(message);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error sending CEC message", e);
+ }
+ }
+
+ public void onHotplugEvent(int port, boolean connected) {
+ if (mCallback == null) {
+ return;
+ }
+
+ HotplugEvent hotplugEvent = new HotplugEvent();
+ hotplugEvent.portId = port;
+ hotplugEvent.connected = connected;
+
+ try {
+ mCallback.onHotplugEvent(hotplugEvent);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error sending hotplug event", e);
+ }
+ }
+
public List<HdmiCecMessage> getResultMessages() {
return new ArrayList<>(mResultMessages);
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
index c60d5fb95846..6e7ec2a88140 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
@@ -70,7 +70,6 @@ public class HdmiCecControllerTest {
}
}
- private HdmiControlService mHdmiControlService;
private HdmiCecController mHdmiCecController;
private int mLogicalAddress = 16;
private AllocateAddressCallback mCallback =
@@ -87,10 +86,11 @@ public class HdmiCecControllerTest {
public void SetUp() {
mMyLooper = mTestLooper.getLooper();
mMyLooper = mTestLooper.getLooper();
- mHdmiControlService = new MyHdmiControlService(InstrumentationRegistry.getTargetContext());
+ HdmiControlService hdmiControlService = new MyHdmiControlService(
+ InstrumentationRegistry.getTargetContext());
mNativeWrapper = new FakeNativeWrapper();
mHdmiCecController = HdmiCecController.createWithNativeWrapper(
- mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter());
+ hdmiControlService, mNativeWrapper, hdmiControlService.getAtomWriter());
}
/** Tests for {@link HdmiCecController#allocateLogicalAddress} */
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index d160a3fab186..498ebf4a2ef9 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -39,7 +39,6 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -370,16 +369,11 @@ public class HdmiCecLocalDevicePlaybackTest {
assertThat(mStandby).isFalse();
}
- // Playback device does not handle routing control related feature right now
- @Ignore("b/120845532")
@Test
- public void handleSetStreamPath_underCurrentDevice() {
- assertThat(mHdmiCecLocalDevicePlayback.getLocalActivePath()).isEqualTo(0);
+ public void handleSetStreamPath() {
HdmiCecMessage message =
HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x2100);
assertThat(mHdmiCecLocalDevicePlayback.handleSetStreamPath(message)).isTrue();
- // TODO(amyjojo): Move set and get LocalActivePath to Control Service.
- assertThat(mHdmiCecLocalDevicePlayback.getLocalActivePath()).isEqualTo(1);
}
@Test
@@ -786,8 +780,8 @@ public class HdmiCecLocalDevicePlaybackTest {
@Test
public void handleSetStreamPath_afterHotplug_broadcastsActiveSource() {
- mHdmiControlService.onHotplug(1, false);
- mHdmiControlService.onHotplug(1, true);
+ mNativeWrapper.onHotplugEvent(1, false);
+ mNativeWrapper.onHotplugEvent(1, true);
HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV,
mPlaybackPhysicalAddress);
@@ -803,8 +797,8 @@ public class HdmiCecLocalDevicePlaybackTest {
@Test
public void handleSetStreamPath_afterHotplug_hasCorrectActiveSource() {
- mHdmiControlService.onHotplug(1, false);
- mHdmiControlService.onHotplug(1, true);
+ mNativeWrapper.onHotplugEvent(1, false);
+ mNativeWrapper.onHotplugEvent(1, true);
HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV,
mPlaybackPhysicalAddress);
diff --git a/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java b/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
index c5d94875b684..c6823ebfd655 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java
@@ -37,6 +37,7 @@ public final class ConversationInfoTest {
private static final Uri CONTACT_URI = Uri.parse("tel:+1234567890");
private static final String PHONE_NUMBER = "+1234567890";
private static final String NOTIFICATION_CHANNEL_ID = "test : abc";
+ private static final String PARENT_NOTIFICATION_CHANNEL_ID = "test";
@Test
public void testBuild() {
@@ -46,6 +47,8 @@ public final class ConversationInfoTest {
.setContactUri(CONTACT_URI)
.setContactPhoneNumber(PHONE_NUMBER)
.setNotificationChannelId(NOTIFICATION_CHANNEL_ID)
+ .setParentNotificationChannelId(PARENT_NOTIFICATION_CHANNEL_ID)
+ .setLastEventTimestamp(100L)
.setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED
| ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)
.setImportant(true)
@@ -62,6 +65,9 @@ public final class ConversationInfoTest {
assertEquals(CONTACT_URI, conversationInfo.getContactUri());
assertEquals(PHONE_NUMBER, conversationInfo.getContactPhoneNumber());
assertEquals(NOTIFICATION_CHANNEL_ID, conversationInfo.getNotificationChannelId());
+ assertEquals(PARENT_NOTIFICATION_CHANNEL_ID,
+ conversationInfo.getParentNotificationChannelId());
+ assertEquals(100L, conversationInfo.getLastEventTimestamp());
assertTrue(conversationInfo.isShortcutLongLived());
assertTrue(conversationInfo.isShortcutCachedForNotification());
assertTrue(conversationInfo.isImportant());
@@ -84,6 +90,8 @@ public final class ConversationInfoTest {
assertNull(conversationInfo.getContactUri());
assertNull(conversationInfo.getContactPhoneNumber());
assertNull(conversationInfo.getNotificationChannelId());
+ assertNull(conversationInfo.getParentNotificationChannelId());
+ assertEquals(0L, conversationInfo.getLastEventTimestamp());
assertFalse(conversationInfo.isShortcutLongLived());
assertFalse(conversationInfo.isShortcutCachedForNotification());
assertFalse(conversationInfo.isImportant());
@@ -103,6 +111,8 @@ public final class ConversationInfoTest {
.setContactUri(CONTACT_URI)
.setContactPhoneNumber(PHONE_NUMBER)
.setNotificationChannelId(NOTIFICATION_CHANNEL_ID)
+ .setParentNotificationChannelId(PARENT_NOTIFICATION_CHANNEL_ID)
+ .setLastEventTimestamp(100L)
.setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED)
.setImportant(true)
.setNotificationSilenced(true)
@@ -122,6 +132,8 @@ public final class ConversationInfoTest {
assertEquals(CONTACT_URI, destination.getContactUri());
assertEquals(PHONE_NUMBER, destination.getContactPhoneNumber());
assertEquals(NOTIFICATION_CHANNEL_ID, destination.getNotificationChannelId());
+ assertEquals(PARENT_NOTIFICATION_CHANNEL_ID, destination.getParentNotificationChannelId());
+ assertEquals(100L, destination.getLastEventTimestamp());
assertTrue(destination.isShortcutLongLived());
assertFalse(destination.isImportant());
assertTrue(destination.isNotificationSilenced());
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index 0a6cd51c3cc5..f37054d269b1 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -29,6 +29,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doAnswer;
@@ -45,6 +46,7 @@ import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Person;
import android.app.job.JobScheduler;
+import android.app.people.ConversationChannel;
import android.app.prediction.AppTarget;
import android.app.prediction.AppTargetEvent;
import android.app.prediction.AppTargetId;
@@ -112,6 +114,7 @@ public final class DataManagerTest {
private static final String CONTACT_URI = "content://com.android.contacts/contacts/lookup/123";
private static final String PHONE_NUMBER = "+1234567890";
private static final String NOTIFICATION_CHANNEL_ID = "test : sc";
+ private static final String PARENT_NOTIFICATION_CHANNEL_ID = "test";
private static final long MILLIS_PER_MINUTE = 1000L * 60L;
@Mock private Context mContext;
@@ -133,10 +136,12 @@ public final class DataManagerTest {
private ScheduledExecutorService mExecutorService;
private NotificationChannel mNotificationChannel;
+ private NotificationChannel mParentNotificationChannel;
private DataManager mDataManager;
private CancellationSignal mCancellationSignal;
private ShortcutChangeCallback mShortcutChangeCallback;
private BroadcastReceiver mShutdownBroadcastReceiver;
+ private ShortcutInfo mShortcutInfo;
private TestInjector mInjector;
@Before
@@ -157,6 +162,11 @@ public final class DataManagerTest {
}).when(mPackageManagerInternal).forEachInstalledPackage(any(Consumer.class), anyInt());
addLocalServiceMock(NotificationManagerInternal.class, mNotificationManagerInternal);
+ mParentNotificationChannel = new NotificationChannel(
+ PARENT_NOTIFICATION_CHANNEL_ID, "test channel",
+ NotificationManager.IMPORTANCE_DEFAULT);
+ when(mNotificationManagerInternal.getNotificationChannel(anyString(), anyInt(),
+ anyString())).thenReturn(mParentNotificationChannel);
when(mContext.getContentResolver()).thenReturn(mContentResolver);
when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
@@ -199,6 +209,7 @@ public final class DataManagerTest {
when(mStatusBarNotification.getUser()).thenReturn(UserHandle.of(USER_ID_PRIMARY));
when(mStatusBarNotification.getPostTime()).thenReturn(System.currentTimeMillis());
when(mNotification.getShortcutId()).thenReturn(TEST_SHORTCUT_ID);
+ when(mNotification.getChannelId()).thenReturn(PARENT_NOTIFICATION_CHANNEL_ID);
mNotificationChannel = new NotificationChannel(
NOTIFICATION_CHANNEL_ID, "test channel", NotificationManager.IMPORTANCE_DEFAULT);
@@ -212,6 +223,13 @@ public final class DataManagerTest {
when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
anyString(), anyInt(), any())).thenReturn(true);
+
+ mShortcutInfo = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ when(mShortcutServiceInternal.getShortcuts(
+ anyInt(), anyString(), anyLong(), anyString(), anyList(), any(), any(),
+ anyInt(), anyInt(), anyInt(), anyInt()))
+ .thenReturn(Collections.singletonList(mShortcutInfo));
verify(mShortcutServiceInternal).addShortcutChangeCallback(
mShortcutChangeCallbackCaptor.capture());
mShortcutChangeCallback = mShortcutChangeCallbackCaptor.getValue();
@@ -417,29 +435,28 @@ public final class DataManagerTest {
List<Range<Long>> activeNotificationOpenTimeSlots = getActiveSlotsForTestShortcut(
Event.NOTIFICATION_EVENT_TYPES);
assertEquals(1, activeNotificationOpenTimeSlots.size());
- verify(mShortcutServiceInternal).uncacheShortcuts(
- anyInt(), any(), eq(TEST_PKG_NAME),
- eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY),
- eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
}
@Test
- public void testNotificationDismissed() {
+ public void testUncacheShortcutsWhenNotificationsDismissed() {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
-
- ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
- buildPerson());
- mDataManager.addOrUpdateConversationInfo(shortcut);
-
NotificationListenerService listenerService =
mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
- // Post one notification.
- shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
- mDataManager.addOrUpdateConversationInfo(shortcut);
- listenerService.onNotificationPosted(mStatusBarNotification);
+ // The cached conversations are above the limit because every conversation has active
+ // notifications. To uncache one of them, the notifications for that conversation need to
+ // be dismissed.
+ for (int i = 0; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
+ String shortcutId = TEST_SHORTCUT_ID + i;
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, shortcutId,
+ buildPerson());
+ shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+ when(mNotification.getShortcutId()).thenReturn(shortcutId);
+ listenerService.onNotificationPosted(mStatusBarNotification);
+ }
- // Post another notification.
+ // Post another notification for the last conversation.
listenerService.onNotificationPosted(mStatusBarNotification);
// Removing one of the two notifications does not un-cache the shortcut.
@@ -452,13 +469,12 @@ public final class DataManagerTest {
listenerService.onNotificationRemoved(mStatusBarNotification, null,
NotificationListenerService.REASON_CANCEL_ALL);
verify(mShortcutServiceInternal).uncacheShortcuts(
- anyInt(), any(), eq(TEST_PKG_NAME),
- eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY),
+ anyInt(), any(), eq(TEST_PKG_NAME), anyList(), eq(USER_ID_PRIMARY),
eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
}
@Test
- public void testShortcutNotUncachedIfNotificationChannelCreated() {
+ public void testConversationIsNotRecentIfCustomized() {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
@@ -472,15 +488,12 @@ public final class DataManagerTest {
shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
mDataManager.addOrUpdateConversationInfo(shortcut);
+ assertEquals(1, mDataManager.getRecentConversations(USER_ID_PRIMARY).size());
+
listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
- listenerService.onNotificationRemoved(mStatusBarNotification, null,
- NotificationListenerService.REASON_CANCEL_ALL);
- verify(mShortcutServiceInternal, never()).uncacheShortcuts(
- anyInt(), any(), eq(TEST_PKG_NAME),
- eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY),
- eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
+ assertTrue(mDataManager.getRecentConversations(USER_ID_PRIMARY).isEmpty());
}
@Test
@@ -561,53 +574,6 @@ public final class DataManagerTest {
}
@Test
- public void testUncacheShortcutWhenShutdown() {
- mDataManager.onUserUnlocked(USER_ID_PRIMARY);
-
- ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
- buildPerson());
- mDataManager.addOrUpdateConversationInfo(shortcut);
-
- NotificationListenerService listenerService =
- mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
-
- listenerService.onNotificationPosted(mStatusBarNotification);
- shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
- mDataManager.addOrUpdateConversationInfo(shortcut);
-
- mShutdownBroadcastReceiver.onReceive(mContext, new Intent());
- verify(mShortcutServiceInternal).uncacheShortcuts(
- anyInt(), any(), eq(TEST_PKG_NAME),
- eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY),
- eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
- }
-
- @Test
- public void testDoNotUncacheShortcutWhenShutdownIfNotificationChannelCreated() {
- mDataManager.onUserUnlocked(USER_ID_PRIMARY);
-
- ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
- buildPerson());
- mDataManager.addOrUpdateConversationInfo(shortcut);
-
- NotificationListenerService listenerService =
- mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
-
- listenerService.onNotificationPosted(mStatusBarNotification);
- shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
- mDataManager.addOrUpdateConversationInfo(shortcut);
-
- listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
- mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
-
- mShutdownBroadcastReceiver.onReceive(mContext, new Intent());
- verify(mShortcutServiceInternal, never()).uncacheShortcuts(
- anyInt(), any(), eq(TEST_PKG_NAME),
- eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY),
- eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
- }
-
- @Test
public void testShortcutAddedOrUpdated() {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
@@ -769,20 +735,57 @@ public final class DataManagerTest {
}
@Test
- public void testPruneInactiveCachedShortcuts() {
+ public void testDoNotUncacheShortcutWithActiveNotifications() {
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
- ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
- buildPerson());
- shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
- mDataManager.addOrUpdateConversationInfo(shortcut);
+ for (int i = 0; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
+ String shortcutId = TEST_SHORTCUT_ID + i;
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, shortcutId,
+ buildPerson());
+ shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+ when(mNotification.getShortcutId()).thenReturn(shortcutId);
+ listenerService.onNotificationPosted(mStatusBarNotification);
+ }
mDataManager.pruneDataForUser(USER_ID_PRIMARY, mCancellationSignal);
+ verify(mShortcutServiceInternal, never()).uncacheShortcuts(
+ anyInt(), anyString(), anyString(), anyList(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void testUncacheOldestCachedShortcut() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+
+ for (int i = 0; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
+ String shortcutId = TEST_SHORTCUT_ID + i;
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, shortcutId,
+ buildPerson());
+ shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+ when(mNotification.getShortcutId()).thenReturn(shortcutId);
+ when(mStatusBarNotification.getPostTime()).thenReturn(100L + i);
+ listenerService.onNotificationPosted(mStatusBarNotification);
+ listenerService.onNotificationRemoved(mStatusBarNotification, null,
+ NotificationListenerService.REASON_CANCEL);
+ }
+
+ // Only the shortcut #0 is uncached, all the others are not.
verify(mShortcutServiceInternal).uncacheShortcuts(
anyInt(), any(), eq(TEST_PKG_NAME),
- eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY),
+ eq(Collections.singletonList(TEST_SHORTCUT_ID + 0)), eq(USER_ID_PRIMARY),
eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
+ for (int i = 1; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
+ verify(mShortcutServiceInternal, never()).uncacheShortcuts(
+ anyInt(), anyString(), anyString(),
+ eq(Collections.singletonList(TEST_SHORTCUT_ID + i)), anyInt(),
+ eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
+ }
}
@Test
@@ -812,6 +815,148 @@ public final class DataManagerTest {
assertEquals(conversationInfo.getShortcutId(), TEST_SHORTCUT_ID);
}
+ @Test
+ public void testGetRecentConversations() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+ listenerService.onNotificationPosted(mStatusBarNotification);
+
+ List<ConversationChannel> result = mDataManager.getRecentConversations(USER_ID_PRIMARY);
+ assertEquals(1, result.size());
+ assertEquals(shortcut.getId(), result.get(0).getShortcutInfo().getId());
+ assertEquals(mParentNotificationChannel.getId(),
+ result.get(0).getParentNotificationChannel().getId());
+ assertEquals(mStatusBarNotification.getPostTime(), result.get(0).getLastEventTimestamp());
+ assertTrue(result.get(0).hasActiveNotifications());
+ }
+
+ @Test
+ public void testGetLastInteraction() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+ listenerService.onNotificationPosted(mStatusBarNotification);
+
+ assertEquals(mStatusBarNotification.getPostTime(),
+ mDataManager.getLastInteraction(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID));
+ assertEquals(0L,
+ mDataManager.getLastInteraction("not_test_pkg", USER_ID_PRIMARY, TEST_SHORTCUT_ID));
+ assertEquals(0L,
+ mDataManager.getLastInteraction(TEST_PKG_NAME, USER_ID_PRIMARY_MANAGED,
+ TEST_SHORTCUT_ID));
+ assertEquals(0L,
+ mDataManager.getLastInteraction(TEST_PKG_NAME, USER_ID_SECONDARY,
+ TEST_SHORTCUT_ID));
+ }
+
+ @Test
+ public void testNonCachedShortcutNotInRecentList() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY_MANAGED,
+ TEST_SHORTCUT_ID, buildPerson());
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+ listenerService.onNotificationPosted(mStatusBarNotification);
+
+ List<ConversationChannel> result = mDataManager.getRecentConversations(USER_ID_PRIMARY);
+ assertTrue(result.isEmpty());
+ }
+
+ @Test
+ public void testCustomizedConversationNotInRecentList() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+
+ // Post a notification and customize the notification settings.
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+ listenerService.onNotificationPosted(mStatusBarNotification);
+ listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
+ mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
+
+ List<ConversationChannel> result = mDataManager.getRecentConversations(USER_ID_PRIMARY);
+ assertTrue(result.isEmpty());
+ }
+
+ @Test
+ public void testRemoveRecentConversation() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+ ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ buildPerson());
+ shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+ mDataManager.addOrUpdateConversationInfo(shortcut);
+
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+ listenerService.onNotificationPosted(mStatusBarNotification);
+ listenerService.onNotificationRemoved(mStatusBarNotification, null,
+ NotificationListenerService.REASON_CANCEL);
+ mDataManager.removeRecentConversation(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
+ USER_ID_PRIMARY);
+
+ verify(mShortcutServiceInternal).uncacheShortcuts(
+ anyInt(), any(), eq(TEST_PKG_NAME), eq(Collections.singletonList(TEST_SHORTCUT_ID)),
+ eq(USER_ID_PRIMARY), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
+ }
+
+ @Test
+ public void testRemoveAllRecentConversations() {
+ mDataManager.onUserUnlocked(USER_ID_PRIMARY);
+
+ ShortcutInfo shortcut1 = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, "1",
+ buildPerson());
+ shortcut1.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+ mDataManager.addOrUpdateConversationInfo(shortcut1);
+
+ ShortcutInfo shortcut2 = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, "2",
+ buildPerson());
+ shortcut2.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
+ mDataManager.addOrUpdateConversationInfo(shortcut2);
+
+ NotificationListenerService listenerService =
+ mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
+
+ // Post a notification and then dismiss it for conversation #1.
+ when(mNotification.getShortcutId()).thenReturn("1");
+ listenerService.onNotificationPosted(mStatusBarNotification);
+ listenerService.onNotificationRemoved(mStatusBarNotification, null,
+ NotificationListenerService.REASON_CANCEL);
+
+ // Post a notification for conversation #2, but don't dismiss it. Its shortcut won't be
+ // uncached when removeAllRecentConversations() is called.
+ when(mNotification.getShortcutId()).thenReturn("2");
+ listenerService.onNotificationPosted(mStatusBarNotification);
+
+ mDataManager.removeAllRecentConversations(USER_ID_PRIMARY);
+
+ verify(mShortcutServiceInternal).uncacheShortcuts(
+ anyInt(), any(), eq(TEST_PKG_NAME), eq(Collections.singletonList("1")),
+ eq(USER_ID_PRIMARY), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
+ verify(mShortcutServiceInternal, never()).uncacheShortcuts(
+ anyInt(), any(), eq(TEST_PKG_NAME), eq(Collections.singletonList("2")),
+ eq(USER_ID_PRIMARY), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
+ }
+
private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
LocalServices.removeServiceForTest(clazz);
LocalServices.addService(clazz, mock);
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 419fb14df340..6febae00f0fb 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -80,6 +80,7 @@ import com.android.server.SystemService;
import com.android.server.lights.LightsManager;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.power.PowerManagerService.BatteryReceiver;
+import com.android.server.power.PowerManagerService.BinderService;
import com.android.server.power.PowerManagerService.Injector;
import com.android.server.power.PowerManagerService.NativeWrapper;
import com.android.server.power.PowerManagerService.UserSwitchedReceiver;
@@ -179,6 +180,7 @@ public class PowerManagerServiceTest {
when(mInattentiveSleepWarningControllerMock.isShown()).thenReturn(false);
when(mDisplayManagerInternalMock.requestPowerState(any(), anyBoolean())).thenReturn(true);
when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), anyString())).thenReturn("");
+ when(mAmbientDisplayConfigurationMock.ambientDisplayAvailable()).thenReturn(true);
mDisplayPowerRequest = new DisplayPowerRequest();
addLocalServiceMock(LightsManager.class, mLightsManagerMock);
@@ -983,6 +985,74 @@ public class PowerManagerServiceTest {
}
@Test
+ public void testIsAmbientDisplaySuppressedForTokenByApp_ambientDisplayUnavailable()
+ throws Exception {
+ createService();
+ when(mAmbientDisplayConfigurationMock.ambientDisplayAvailable()).thenReturn(false);
+
+ BinderService service = mService.getBinderServiceInstance();
+ assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", Binder.getCallingUid()))
+ .isFalse();
+ }
+
+ @Test
+ public void testIsAmbientDisplaySuppressedForTokenByApp_default()
+ throws Exception {
+ createService();
+
+ BinderService service = mService.getBinderServiceInstance();
+ assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", Binder.getCallingUid()))
+ .isFalse();
+ }
+
+ @Test
+ public void testIsAmbientDisplaySuppressedForTokenByApp_suppressedByCallingApp()
+ throws Exception {
+ createService();
+ BinderService service = mService.getBinderServiceInstance();
+ service.suppressAmbientDisplay("test", true);
+
+ assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", Binder.getCallingUid()))
+ .isTrue();
+ // Check that isAmbientDisplaySuppressedForTokenByApp doesn't return true for another app.
+ assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", /* appUid= */ 123))
+ .isFalse();
+ }
+
+ @Test
+ public void testIsAmbientDisplaySuppressedForTokenByApp_notSuppressedByCallingApp()
+ throws Exception {
+ createService();
+ BinderService service = mService.getBinderServiceInstance();
+ service.suppressAmbientDisplay("test", false);
+
+ assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", Binder.getCallingUid()))
+ .isFalse();
+ // Check that isAmbientDisplaySuppressedForTokenByApp doesn't return true for another app.
+ assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test", /* appUid= */ 123))
+ .isFalse();
+ }
+
+ @Test
+ public void testIsAmbientDisplaySuppressedForTokenByApp_multipleTokensSuppressedByCallingApp()
+ throws Exception {
+ createService();
+ BinderService service = mService.getBinderServiceInstance();
+ service.suppressAmbientDisplay("test1", true);
+ service.suppressAmbientDisplay("test2", true);
+
+ assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test1", Binder.getCallingUid()))
+ .isTrue();
+ assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test2", Binder.getCallingUid()))
+ .isTrue();
+ // Check that isAmbientDisplaySuppressedForTokenByApp doesn't return true for another app.
+ assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test1", /* appUid= */ 123))
+ .isFalse();
+ assertThat(service.isAmbientDisplaySuppressedForTokenByApp("test2", /* appUid= */ 123))
+ .isFalse();
+ }
+
+ @Test
public void testSetPowerBoost_redirectsCallToNativeWrapper() {
createService();
mService.systemReady(null);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index f10cab87a4fe..3af873d46026 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1522,7 +1522,7 @@ public class ActivityRecordTests extends WindowTestsBase {
try {
// Return error to skip unnecessary operation.
doReturn(WindowManagerGlobal.ADD_STARTING_NOT_NEEDED).when(session).addToDisplay(
- any() /* window */, anyInt() /* seq */, any() /* attrs */,
+ any() /* window */, any() /* attrs */,
anyInt() /* viewVisibility */, anyInt() /* displayId */, any() /* outFrame */,
any() /* outContentInsets */, any() /* outStableInsets */,
any() /* outDisplayCutout */, any() /* outInputChannel */,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
index ca739c0dd389..91cfd4e6a89d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
@@ -56,4 +56,12 @@ public class ImeInsetsSourceProviderTest extends WindowTestsBase {
mImeProvider.scheduleShowImePostLayout(appWin);
assertTrue(mImeProvider.isImeTargetFromDisplayContentAndImeSame());
}
+
+ @Test
+ public void testInputMethodInputTargetCanShowIme() {
+ WindowState target = createWindow(null, TYPE_APPLICATION, "app");
+ mDisplayContent.mInputMethodTarget = target;
+ mImeProvider.scheduleShowImePostLayout(target);
+ assertTrue(mImeProvider.isImeTargetFromDisplayContentAndImeSame());
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 3053fe6ec55f..cc8b2a1bb392 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -173,6 +173,35 @@ public class RootWindowContainerTests extends WindowTestsBase {
}
@Test
+ public void testTaskLayerRank() {
+ final Task rootTask = new TaskBuilder(mSupervisor).build();
+ final Task task1 = new TaskBuilder(mSupervisor).setParentTask(rootTask).build();
+ new ActivityBuilder(mAtm).setStack(task1).build().mVisibleRequested = true;
+ // RootWindowContainer#invalidateTaskLayers should post to update.
+ waitHandlerIdle(mWm.mH);
+
+ assertEquals(1, task1.mLayerRank);
+ // Only tasks that directly contain activities have a ranking.
+ assertEquals(Task.LAYER_RANK_INVISIBLE, rootTask.mLayerRank);
+
+ final Task task2 = new TaskBuilder(mSupervisor).build();
+ new ActivityBuilder(mAtm).setStack(task2).build().mVisibleRequested = true;
+ waitHandlerIdle(mWm.mH);
+
+ // Note that ensureActivitiesVisible is disabled in SystemServicesTestRule, so both the
+ // activities have the visible rank.
+ assertEquals(2, task1.mLayerRank);
+ // The task2 is the top task, so it has a lower rank as a higher priority oom score.
+ assertEquals(1, task2.mLayerRank);
+
+ task2.moveToBack("test", null /* task */);
+ waitHandlerIdle(mWm.mH);
+
+ assertEquals(1, task1.mLayerRank);
+ assertEquals(2, task2.mLayerRank);
+ }
+
+ @Test
public void testForceStopPackage() {
final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
final ActivityRecord activity = task.getTopMostActivity();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index d37f3f402c30..ea1223312cb2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -94,11 +94,6 @@ public class TestIWindow extends IWindow.Stub {
}
@Override
- public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility, int localValue,
- int localChanges) throws RemoteException {
- }
-
- @Override
public void dispatchWindowShown() throws RemoteException {
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index 38c7531f5f5d..e50c00975a7f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -277,6 +277,69 @@ public class WindowProcessControllerTests extends WindowTestsBase {
mWpc.getConfiguration().seq, globalSeq);
}
+ @Test
+ public void testComputeOomAdjFromActivities() {
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setCreateTask(true)
+ .setUseProcess(mWpc)
+ .build();
+ activity.mVisibleRequested = true;
+ final int[] callbackResult = { 0 };
+ final int visible = 1;
+ final int paused = 2;
+ final int stopping = 4;
+ final int other = 8;
+ final WindowProcessController.ComputeOomAdjCallback callback =
+ new WindowProcessController.ComputeOomAdjCallback() {
+ @Override
+ public void onVisibleActivity() {
+ callbackResult[0] |= visible;
+ }
+
+ @Override
+ public void onPausedActivity() {
+ callbackResult[0] |= paused;
+ }
+
+ @Override
+ public void onStoppingActivity(boolean finishing) {
+ callbackResult[0] |= stopping;
+ }
+
+ @Override
+ public void onOtherActivity() {
+ callbackResult[0] |= other;
+ }
+ };
+
+ // onStartActivity should refresh the state immediately.
+ mWpc.onStartActivity(0 /* topProcessState */, activity.info);
+ assertEquals(1 /* minTaskLayer */, mWpc.computeOomAdjFromActivities(callback));
+ assertEquals(visible, callbackResult[0]);
+
+ // The oom state will be updated in handler from activity state change.
+ callbackResult[0] = 0;
+ activity.mVisibleRequested = false;
+ activity.setState(Task.ActivityState.PAUSED, "test");
+ waitHandlerIdle(mAtm.mH);
+ mWpc.computeOomAdjFromActivities(callback);
+ assertEquals(paused, callbackResult[0]);
+
+ // updateProcessInfo with updateOomAdj=true should refresh the state immediately.
+ callbackResult[0] = 0;
+ activity.setState(Task.ActivityState.STOPPING, "test");
+ mWpc.updateProcessInfo(false /* updateServiceConnectionActivities */,
+ true /* activityChange */, true /* updateOomAdj */, false /* addPendingTopUid */);
+ mWpc.computeOomAdjFromActivities(callback);
+ assertEquals(stopping, callbackResult[0]);
+
+ callbackResult[0] = 0;
+ activity.setState(Task.ActivityState.STOPPED, "test");
+ waitHandlerIdle(mAtm.mH);
+ mWpc.computeOomAdjFromActivities(callback);
+ assertEquals(other, callbackResult[0]);
+ }
+
private TestDisplayContent createTestDisplayContentInContainer() {
return new TestDisplayContent.Builder(mAtm, 1000, 1500).build();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 7daddd8720ab..986807e661f1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -360,7 +360,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
attrs.setTitle(name);
final WindowState w = new WindowState(service, session, iWindow, token, parent,
- OP_NONE, 0, attrs, VISIBLE, ownerId, userId,
+ OP_NONE, attrs, VISIBLE, ownerId, userId,
ownerCanAddInternalSystemWindow,
powerManagerWrapper);
// TODO: Probably better to make this call in the WindowState ctor to avoid errors with
@@ -1088,7 +1088,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
TestWindowState(WindowManagerService service, Session session, IWindow window,
WindowManager.LayoutParams attrs, WindowToken token) {
- super(service, session, window, token, null, OP_NONE, 0, attrs, 0, 0, 0,
+ super(service, session, window, token, null, OP_NONE, attrs, 0, 0, 0,
false /* ownerCanAddInternalSystemWindow */);
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 5b3da615d4be..8261b53a2c9f 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -79,6 +79,30 @@ public class CarrierConfigManager {
*/
public static final int SERVICE_CLASS_VOICE = ImsSsData.SERVICE_CLASS_VOICE;
+ /**
+ * Only send USSD over IMS while CS is out of service, otherwise send USSD over CS.
+ * {@link #KEY_CARRIER_USSD_METHOD_INT}
+ */
+ public static final int USSD_OVER_CS_PREFERRED = 0;
+
+ /**
+ * Send USSD over IMS or CS while IMS is out of service or silent redial over CS if needed.
+ * {@link #KEY_CARRIER_USSD_METHOD_INT}
+ */
+ public static final int USSD_OVER_IMS_PREFERRED = 1;
+
+ /**
+ * Only send USSD over CS.
+ * {@link #KEY_CARRIER_USSD_METHOD_INT}
+ */
+ public static final int USSD_OVER_CS_ONLY = 2;
+
+ /**
+ * Only send USSD over IMS and disallow silent redial over CS.
+ * {@link #KEY_CARRIER_USSD_METHOD_INT}
+ */
+ public static final int USSD_OVER_IMS_ONLY = 3;
+
private final Context mContext;
/**
@@ -584,6 +608,20 @@ public class CarrierConfigManager {
public static final String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
/**
+ * Specify the method of selection for UE sending USSD requests. The default value is
+ * {@link #USSD_OVER_CS_PREFERRED}.
+ * <p> Available options:
+ * <ul>
+ * <li>0: {@link #USSD_OVER_CS_PREFERRED} </li>
+ * <li>1: {@link #USSD_OVER_IMS_PREFERRED} </li>
+ * <li>2: {@link #USSD_OVER_CS_ONLY} </li>
+ * <li>3: {@link #USSD_OVER_IMS_ONLY} </li>
+ * </ul>
+ */
+ public static final String KEY_CARRIER_USSD_METHOD_INT =
+ "carrier_ussd_method_int";
+
+ /**
* Flag specifying whether to show an alert dialog for 5G disable when the user disables VoLTE.
* By default this value is {@code false}.
*
@@ -3963,6 +4001,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_CARRIER_SETTINGS_ENABLE_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_VOLTE_AVAILABLE_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_VT_AVAILABLE_BOOL, false);
+ sDefaults.putInt(KEY_CARRIER_USSD_METHOD_INT, USSD_OVER_CS_PREFERRED);
sDefaults.putBoolean(KEY_VOLTE_5G_LIMITED_ALERT_DIALOG_BOOL, false);
sDefaults.putBoolean(KEY_NOTIFY_HANDOVER_VIDEO_FROM_WIFI_TO_LTE_BOOL, false);
sDefaults.putBoolean(KEY_ALLOW_MERGING_RTT_CALLS_BOOL, false);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a82d98807ad3..11c1aa0ac132 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2807,7 +2807,11 @@ public class TelephonyManager {
/** Current network is LTE_CA {@hide} */
@UnsupportedAppUsage
public static final int NETWORK_TYPE_LTE_CA = TelephonyProtoEnums.NETWORK_TYPE_LTE_CA; // = 19.
- /** Current network is NR(New Radio) 5G. */
+ /**
+ * Current network is NR (New Radio) 5G.
+ * This will only be returned for 5G SA.
+ * For 5G NSA, the network type will be {@link #NETWORK_TYPE_LTE}.
+ */
public static final int NETWORK_TYPE_NR = TelephonyProtoEnums.NETWORK_TYPE_NR; // 20.
private static final @NetworkType int[] NETWORK_TYPES = {
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index 3c3076f11727..030ddd2792bb 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -32,7 +32,6 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.net.LinkProperties.ProvisioningChange;
-import android.net.util.LinkPropertiesUtils.CompareResult;
import android.os.Build;
import android.system.OsConstants;
import android.util.ArraySet;
@@ -41,6 +40,7 @@ import androidx.core.os.BuildCompat;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
index 91c9a2a38036..6de31f6b4be1 100644
--- a/tests/net/java/android/net/MacAddressTest.java
+++ b/tests/net/java/android/net/MacAddressTest.java
@@ -22,11 +22,11 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.net.util.MacAddressUtils;
-
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.net.module.util.MacAddressUtils;
+
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 391be357e963..0973d545fd37 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -29,7 +29,6 @@ import android.net.NetworkSpecifier;
import android.net.ProxyInfo;
import android.net.StaticIpConfiguration;
import android.net.Uri;
-import android.net.util.MacAddressUtils;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -41,6 +40,7 @@ import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.net.module.util.MacAddressUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
index dad431c1ca2c..e2f40cfa058c 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
@@ -17,10 +17,11 @@
package android.net.wifi.p2p.nsd;
import android.compat.annotation.UnsupportedAppUsage;
-import android.net.util.nsd.DnsSdTxtRecord;
import android.os.Build;
import android.text.TextUtils;
+import com.android.net.module.util.DnsSdTxtRecord;
+
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
diff --git a/wifi/java/android/net/wifi/util/SdkLevelUtil.java b/wifi/java/android/net/wifi/util/SdkLevelUtil.java
index 042634c7125c..d08d4fd742b7 100644
--- a/wifi/java/android/net/wifi/util/SdkLevelUtil.java
+++ b/wifi/java/android/net/wifi/util/SdkLevelUtil.java
@@ -23,17 +23,17 @@ import android.os.Build;
*
* This can be used to disable new Wifi APIs added in Mainline updates on older SDK versions.
*
+ * Note: if certain functionality is gated with SdkLevelUtil, its corresponding unit tests should
+ * also be gated by the same condition. Then, those unit tests will only be exercised on a base
+ * system image satisfying that condition.
+ * Alternatively, it can be tested via static mocking.
+ *
* @hide
*/
public class SdkLevelUtil {
- /** This class is instantiable to allow easy mocking. */
- public SdkLevelUtil() { }
-
- /** See {@link #isAtLeastS()}. This version is non-static to allow easy mocking. */
- public boolean isAtLeastSMockable() {
- return isAtLeastS();
- }
+ /** This class is not instantiable. */
+ private SdkLevelUtil() {}
/** Returns true if the Android platform SDK is at least "S", false otherwise. */
public static boolean isAtLeastS() {
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 62220a6237b1..d4b20519215c 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -33,13 +33,14 @@ import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import android.net.MacAddress;
-import android.net.util.MacAddressUtils;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
import android.os.Parcel;
import androidx.test.filters.SmallTest;
+import com.android.net.module.util.MacAddressUtils;
+
import org.junit.Before;
import org.junit.Test;