summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp3
-rw-r--r--apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java11
-rw-r--r--apex/statsd/Android.bp4
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java3
-rw-r--r--core/java/android/content/pm/PackageInstaller.java20
-rw-r--r--core/java/android/content/pm/PackageManager.java3
-rw-r--r--core/java/android/widget/ProgressBar.java8
-rw-r--r--core/java/com/android/internal/jank/FrameTracker.java77
-rw-r--r--core/java/com/android/internal/jank/InteractionJankMonitor.java22
-rw-r--r--core/java/com/android/internal/util/LatencyTracker.java50
-rw-r--r--core/jni/android_view_KeyCharacterMap.cpp54
-rw-r--r--core/jni/android_view_KeyCharacterMap.h2
-rw-r--r--core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java122
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java)134
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java45
-rw-r--r--media/jni/Android.bp23
-rw-r--r--media/jni/android_media_MediaTranscodeManager.cpp125
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_apps.xml12
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_apps_selected.xml6
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_home.xml25
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_home_selected.xml25
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_hvac.xml44
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_hvac_selected.xml25
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_notification.xml8
-rw-r--r--packages/CarSystemUI/res/drawable/car_ic_user_icon.xml25
-rw-r--r--packages/CarSystemUI/res/drawable/hvac_decrease_button.xml53
-rw-r--r--packages/CarSystemUI/res/drawable/hvac_increase_button.xml53
-rw-r--r--packages/CarSystemUI/res/drawable/ic_mic_white.xml10
-rw-r--r--packages/CarSystemUI/res/layout/adjustable_temperature_view.xml50
-rw-r--r--packages/CarSystemUI/res/layout/car_navigation_bar.xml203
-rw-r--r--packages/CarSystemUI/res/layout/car_top_navigation_bar.xml100
-rw-r--r--packages/CarSystemUI/res/layout/car_top_navigation_bar_unprovisioned.xml8
-rw-r--r--packages/CarSystemUI/res/values/colors.xml3
-rw-r--r--packages/CarSystemUI/res/values/config.xml1
-rw-r--r--packages/CarSystemUI/res/values/dimens.xml15
-rw-r--r--packages/CarSystemUI/res/values/strings.xml2
-rw-r--r--packages/CarSystemUI/res/values/styles.xml24
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java7
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java108
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/hvac/AnimatedTemperatureView.java48
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java175
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextView.java29
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureView.java29
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java6
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/statusbar/UserNameViewController.java132
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java174
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java76
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/TemperatureTextViewTest.java107
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java5
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/statusbar/UserNameViewControllerTest.java155
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java2
-rw-r--r--packages/SystemUI/AndroidManifest.xml2
-rw-r--r--packages/SystemUI/README.md4
-rw-r--r--packages/SystemUI/res/layout-land-television/volume_dialog.xml9
-rw-r--r--packages/SystemUI/res/layout-land-television/volume_dialog_row.xml40
-rw-r--r--packages/SystemUI/res/values-land-television/dimens.xml5
-rw-r--r--packages/SystemUI/res/values-television/config.xml1
-rw-r--r--packages/SystemUI/res/values-television/integers.xml7
-rw-r--r--packages/SystemUI/res/values/config.xml1
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/ExpandHelper.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/Pip.java170
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipUI.java122
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java (renamed from packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java)78
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipModule.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java (renamed from packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java)96
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java66
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/dagger/PipModule.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java108
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java52
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java88
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java13
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java6
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java4
-rw-r--r--services/core/java/com/android/server/am/AppErrors.java142
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java6
-rw-r--r--services/core/java/com/android/server/audio/AudioEventLogger.java31
-rwxr-xr-xservices/core/java/com/android/server/audio/AudioService.java109
-rw-r--r--services/core/java/com/android/server/hdmi/ActiveSourceAction.java2
-rw-r--r--services/core/java/com/android/server/hdmi/ActiveSourceHandler.java8
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecController.java12
-rwxr-xr-xservices/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java59
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java3
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java6
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java12
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java16
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java17
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssLocationProvider.java4
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java29
-rw-r--r--services/core/java/com/android/server/pm/AppsFilter.java4
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java63
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java14
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java14
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java602
-rw-r--r--services/core/java/com/android/server/wm/Task.java3
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp15
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp23
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java79
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java23
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java9
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java27
-rw-r--r--tests/FlickerTests/Android.bp23
-rw-r--r--tests/FlickerTests/AndroidTestPhysicalDevices.xml (renamed from tests/FlickerTests/AndroidTest.xml)1
-rw-r--r--tests/FlickerTests/AndroidTestVirtualDevices.xml41
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt5
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt4
-rw-r--r--tests/SilkFX/Android.bp6
-rw-r--r--tests/SilkFX/AndroidManifest.xml3
-rw-r--r--tests/SilkFX/res/drawable-hdpi/background1.jpegbin0 -> 200459 bytes
-rw-r--r--tests/SilkFX/res/drawable-hdpi/background2.jpegbin0 -> 110703 bytes
-rw-r--r--tests/SilkFX/res/drawable-hdpi/background3.jpegbin0 -> 318853 bytes
-rw-r--r--tests/SilkFX/res/drawable-hdpi/noise.pngbin0 -> 494875 bytes
-rw-r--r--tests/SilkFX/res/layout/activity_glass.xml246
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/Main.kt4
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt126
-rw-r--r--tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt117
-rw-r--r--tools/validatekeymaps/Main.cpp16
162 files changed, 3688 insertions, 2037 deletions
diff --git a/Android.bp b/Android.bp
index 8475fbd87c09..e756b3428164 100644
--- a/Android.bp
+++ b/Android.bp
@@ -333,7 +333,6 @@ filegroup {
":installd_aidl",
":keystore_aidl",
":libaudioclient_aidl",
- ":mediatranscoding_aidl_interface-java-source",
":libbinder_aidl",
":libbluetooth-binder-aidl",
":libcamera_client_aidl",
@@ -577,6 +576,7 @@ java_library {
// If MimeMap ever becomes its own APEX, then this dependency would need to be removed
// in favor of an API stubs dependency in java_library "framework" below.
"mimemap",
+ "mediatranscoding_aidl_interface-java",
],
// For backwards compatibility.
stem: "framework",
@@ -623,6 +623,7 @@ java_library {
static_libs: [
"exoplayer2-extractor",
"android.hardware.wifi-V1.0-java-constants",
+ "mediatranscoding_aidl_interface-java",
// Additional dependencies needed to build the ike API classes.
"ike-internals",
diff --git a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java
index b1dbb28c9501..d07ed375b2ab 100644
--- a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java
+++ b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java
@@ -51,13 +51,14 @@ public class MyContentCaptureService extends ContentCaptureService {
sServiceWatcher = null;
}
- public static void clearServiceWatcher() {
- if (sServiceWatcher != null) {
- if (sServiceWatcher.mReadyToClear) {
- sServiceWatcher.mService = null;
+ private static void clearServiceWatcher() {
+ final ServiceWatcher sw = sServiceWatcher;
+ if (sw != null) {
+ if (sw.mReadyToClear) {
+ sw.mService = null;
sServiceWatcher = null;
} else {
- sServiceWatcher.mReadyToClear = true;
+ sw.mReadyToClear = true;
}
}
}
diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp
index e75fa88c54fe..ede8852c5905 100644
--- a/apex/statsd/Android.bp
+++ b/apex/statsd/Android.bp
@@ -19,8 +19,10 @@ apex {
}
apex_defaults {
- native_shared_libs: [
+ jni_libs: [
"libstats_jni",
+ ],
+ native_shared_libs: [
"libstatspull",
"libstatssocket",
],
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 98de85d9735d..7b3d9f113bda 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -11992,6 +11992,9 @@ public class DevicePolicyManager {
* </ul>
* Common Criteria mode is disabled by default.
*
+ * <p><em>Note:</em> if Common Critera mode is turned off after being enabled previously,
+ * all existing WiFi configurations will be lost.
+ *
* @param admin which {@link DeviceAdminReceiver} this request is associated with.
* @param enabled whether Common Criteria mode should be enabled or not.
*/
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index b7c3289b6e66..e6ea04433114 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2512,12 +2512,16 @@ public class PackageInstaller {
}
/**
- * If {@link SessionParams#setInstallAsInstantApp(boolean)} was called with {@code true},
- * return true. If it was called with {@code false} or if it was not called return false.
+ * Get if this session is to be installed as Instant Apps.
*
- * @hide
+ * @param isInstantApp an unused parameter and is ignored.
+ * @return {@code true} if {@link SessionParams#setInstallAsInstantApp(boolean)} was called
+ * with {@code true}; {@code false} if it was called with {@code false} or if it was not
+ * called.
*
* @see #getInstallAsFullApp
+ *
+ * @hide
*/
@SystemApi
public boolean getInstallAsInstantApp(boolean isInstantApp) {
@@ -2525,12 +2529,16 @@ public class PackageInstaller {
}
/**
- * If {@link SessionParams#setInstallAsInstantApp(boolean)} was called with {@code false},
- * return true. If it was called with {@code true} or if it was not called return false.
+ * Get if this session is to be installed as full apps.
*
- * @hide
+ * @param isInstantApp an unused parameter and is ignored.
+ * @return {@code true} if {@link SessionParams#setInstallAsInstantApp(boolean)} was called
+ * with {@code false}; {code false} if it was called with {@code true} or if it was not
+ * called.
*
* @see #getInstallAsInstantApp
+ *
+ * @hide
*/
@SystemApi
public boolean getInstallAsFullApp(boolean isInstantApp) {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d672c6ac6c2f..d2395ec9f69f 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1155,7 +1155,8 @@ public abstract class PackageManager {
/**
* Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
- * if the new package uses a shared library that is not available.
+ * when the package being replaced is a system app and the caller didn't provide the
+ * {@link #DELETE_SYSTEM_APP} flag.
*
* @hide
*/
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 35605c4c6f6e..796654a4dc99 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -54,6 +54,7 @@ import android.view.View;
import android.view.ViewDebug;
import android.view.ViewHierarchyEncoder;
import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
@@ -314,9 +315,6 @@ public class ProgressBar extends View {
setMax(a.getInt(R.styleable.ProgressBar_max, mMax));
setProgress(a.getInt(R.styleable.ProgressBar_progress, mProgress));
- // onProgressRefresh() is only called when the progress changes. So we should set
- // stateDescription during initialization here.
- super.setStateDescription(formatStateDescription(mProgress));
setSecondaryProgress(a.getInt(
R.styleable.ProgressBar_secondaryProgress, mSecondaryProgress));
@@ -1627,7 +1625,8 @@ public class ProgressBar extends View {
}
void onProgressRefresh(float scale, boolean fromUser, int progress) {
- if (mCustomStateDescription == null) {
+ if (AccessibilityManager.getInstance(mContext).isEnabled()
+ && mCustomStateDescription == null) {
super.setStateDescription(formatStateDescription(mProgress));
}
}
@@ -2351,6 +2350,7 @@ public class ProgressBar extends View {
AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_INT, getMin(), getMax(),
getProgress());
info.setRangeInfo(rangeInfo);
+ info.setStateDescription(formatStateDescription(mProgress));
}
}
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index f9a2ecc10dc8..e5c845059a0d 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -26,6 +26,7 @@ import android.view.ThreadedRenderer;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor.Session;
+import com.android.internal.util.FrameworkStatsLog;
/**
* @hide
@@ -34,18 +35,19 @@ public class FrameTracker implements HardwareRendererObserver.OnFrameMetricsAvai
private static final String TAG = FrameTracker.class.getSimpleName();
private static final boolean DEBUG = false;
//TODO (163431584): need also consider other refresh rates.
- private static final long CRITERIA = 1000000000 / 60;
- @VisibleForTesting
- public static final long UNKNOWN_TIMESTAMP = -1;
+ private static final long JANK_THRESHOLD_NANOS = 1000000000 / 60;
+ private static final long UNKNOWN_TIMESTAMP = -1;
- @VisibleForTesting
- public long mBeginTime = UNKNOWN_TIMESTAMP;
- @VisibleForTesting
- public long mEndTime = UNKNOWN_TIMESTAMP;
- public boolean mShouldTriggerTrace;
- public HardwareRendererObserver mObserver;
- public ThreadedRendererWrapper mRendererWrapper;
- public FrameMetricsWrapper mMetricsWrapper;
+ private final HardwareRendererObserver mObserver;
+ private final ThreadedRendererWrapper mRendererWrapper;
+ private final FrameMetricsWrapper mMetricsWrapper;
+
+ private long mBeginTime = UNKNOWN_TIMESTAMP;
+ private long mEndTime = UNKNOWN_TIMESTAMP;
+ private boolean mShouldTriggerTrace;
+ private long mTotalFramesCount = 0;
+ private long mMissedFramesCount = 0;
+ private long mMaxFrameTimeNanos = 0;
private Session mSession;
@@ -108,37 +110,6 @@ public class FrameTracker implements HardwareRendererObserver.OnFrameMetricsAvai
Trace.endAsyncSection(mSession.getName(), (int) mBeginTime);
}
- /**
- * Check if we had a janky frame according to the metrics.
- * @param metrics frame metrics
- * @return true if it is a janky frame
- */
- @VisibleForTesting
- public boolean isJankyFrame(FrameMetricsWrapper metrics) {
- long totalDurationMs = metrics.getMetric(FrameMetrics.TOTAL_DURATION);
- boolean isFirstFrame = metrics.getMetric(FrameMetrics.FIRST_DRAW_FRAME) == 1;
- boolean isJanky = !isFirstFrame && totalDurationMs - CRITERIA > 0;
-
- if (DEBUG) {
- StringBuilder sb = new StringBuilder();
- sb.append(isJanky).append(",");
- sb.append(metrics.getMetric(FrameMetrics.FIRST_DRAW_FRAME)).append(",");
- sb.append(metrics.getMetric(FrameMetrics.INPUT_HANDLING_DURATION)).append(",");
- sb.append(metrics.getMetric(FrameMetrics.ANIMATION_DURATION)).append(",");
- sb.append(metrics.getMetric(FrameMetrics.LAYOUT_MEASURE_DURATION)).append(",");
- sb.append(metrics.getMetric(FrameMetrics.DRAW_DURATION)).append(",");
- sb.append(metrics.getMetric(FrameMetrics.SYNC_DURATION)).append(",");
- sb.append(metrics.getMetric(FrameMetrics.COMMAND_ISSUE_DURATION)).append(",");
- sb.append(metrics.getMetric(FrameMetrics.SWAP_BUFFERS_DURATION)).append(",");
- sb.append(totalDurationMs).append(",");
- sb.append(metrics.getMetric(FrameMetrics.INTENDED_VSYNC_TIMESTAMP)).append(",");
- sb.append(metrics.getMetric(FrameMetrics.VSYNC_TIMESTAMP)).append(",");
- Log.v(TAG, "metrics=" + sb.toString());
- }
-
- return isJanky;
- }
-
@Override
public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) {
// Since this callback might come a little bit late after the end() call.
@@ -160,11 +131,29 @@ public class FrameTracker implements HardwareRendererObserver.OnFrameMetricsAvai
}
triggerPerfetto();
}
+ if (mSession.logToStatsd()) {
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.UI_INTERACTION_FRAME_INFO_REPORTED,
+ mSession.getStatsdInteractionType(),
+ mTotalFramesCount,
+ mMissedFramesCount,
+ mMaxFrameTimeNanos);
+ }
return;
}
- // The frame is in the duration of the CUJ, check if it catches the deadline.
- if (isJankyFrame(mMetricsWrapper)) {
+ long totalDurationNanos = mMetricsWrapper.getMetric(FrameMetrics.TOTAL_DURATION);
+ boolean isFirstFrame = mMetricsWrapper.getMetric(FrameMetrics.FIRST_DRAW_FRAME) == 1;
+ boolean isJankyFrame = !isFirstFrame && totalDurationNanos > JANK_THRESHOLD_NANOS;
+
+ mTotalFramesCount += 1;
+
+ if (!isFirstFrame) {
+ mMaxFrameTimeNanos = Math.max(totalDurationNanos, mMaxFrameTimeNanos);
+ }
+
+ if (isJankyFrame) {
+ mMissedFramesCount += 1;
mShouldTriggerTrace = true;
}
}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 6bfb178bc102..5a0cbf9e93e4 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -16,6 +16,8 @@
package com.android.internal.jank;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.os.HandlerThread;
@@ -37,9 +39,20 @@ public class InteractionJankMonitor {
private static final String TAG = InteractionJankMonitor.class.getSimpleName();
private static final boolean DEBUG = false;
private static final Object LOCK = new Object();
+
+ // Every value must have a corresponding entry in CUJ_STATSD_INTERACTION_TYPE.
public static final int CUJ_NOTIFICATION_SHADE_MOTION = 0;
public static final int CUJ_NOTIFICATION_SHADE_GESTURE = 1;
+ private static final int NO_STATSD_LOGGING = -1;
+
+ // Used to convert CujType to InteractionType enum value for statsd logging.
+ // Use NO_STATSD_LOGGING in case the measurement for a given CUJ should not be logged to statsd.
+ private static final int[] CUJ_TO_STATSD_INTERACTION_TYPE = {
+ NO_STATSD_LOGGING,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE,
+ };
+
private static ThreadedRenderer sRenderer;
private static Map<String, FrameTracker> sRunningTracker;
private static HandlerThread sWorker;
@@ -173,6 +186,15 @@ public class InteractionJankMonitor {
return mId;
}
+ public int getStatsdInteractionType() {
+ return CUJ_TO_STATSD_INTERACTION_TYPE[mId];
+ }
+
+ /** Describes whether the measurement from this session should be written to statsd. */
+ public boolean logToStatsd() {
+ return getStatsdInteractionType() != NO_STATSD_LOGGING;
+ }
+
public String getName() {
return "CujType<" + mId + ">";
}
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index 67cfc3a7dd49..555f62c53387 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -14,13 +14,9 @@
package com.android.internal.util;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.os.Build;
import android.os.SystemClock;
-import android.os.SystemProperties;
import android.os.Trace;
import android.util.EventLog;
import android.util.Log;
@@ -29,18 +25,14 @@ import android.util.SparseLongArray;
import com.android.internal.logging.EventLogTags;
/**
- * Class to track various latencies in SystemUI. It then outputs the latency to logcat so these
- * latencies can be captured by tests and then used for dashboards.
+ * Class to track various latencies in SystemUI. It then writes the latency to statsd and also
+ * outputs it to logcat so these latencies can be captured by tests and then used for dashboards.
* <p>
* This is currently only in Keyguard so it can be shared between SystemUI and Keyguard, but
* eventually we'd want to merge these two packages together so Keyguard can use common classes
* that are shared with SystemUI.
*/
public class LatencyTracker {
-
- private static final String ACTION_RELOAD_PROPERTY =
- "com.android.systemui.RELOAD_LATENCY_TRACKER_PROPERTY";
-
private static final String TAG = "LatencyTracker";
/**
@@ -82,7 +74,7 @@ public class LatencyTracker {
/*
* Time between we get a face acquired signal until we start with the unlock animation
*/
- public static final int ACTION_FACE_WAKE_AND_UNLOCK = 6;
+ public static final int ACTION_FACE_WAKE_AND_UNLOCK = 7;
private static final String[] NAMES = new String[] {
"expand panel",
@@ -94,38 +86,34 @@ public class LatencyTracker {
"rotate the screen",
"face wake-and-unlock" };
+ private static final int[] STATSD_ACTION = new int[] {
+ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL,
+ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TOGGLE_RECENTS,
+ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FINGERPRINT_WAKE_AND_UNLOCK,
+ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL,
+ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL_UNLOCKED,
+ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TURN_ON_SCREEN,
+ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_ROTATE_SCREEN,
+ FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FACE_WAKE_AND_UNLOCK,
+ };
+
private static LatencyTracker sLatencyTracker;
private final SparseLongArray mStartRtc = new SparseLongArray();
- private boolean mEnabled;
public static LatencyTracker getInstance(Context context) {
if (sLatencyTracker == null) {
- sLatencyTracker = new LatencyTracker(context.getApplicationContext());
+ sLatencyTracker = new LatencyTracker();
}
return sLatencyTracker;
}
- private LatencyTracker(Context context) {
- context.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- reloadProperty();
- }
- }, new IntentFilter(ACTION_RELOAD_PROPERTY));
- reloadProperty();
- }
-
- private void reloadProperty() {
- mEnabled = SystemProperties.getBoolean("debug.systemui.latency_tracking", false);
- }
-
public static boolean isEnabled(Context ctx) {
return getInstance(ctx).isEnabled();
}
public boolean isEnabled() {
- return Build.IS_DEBUGGABLE && mEnabled;
+ return Build.IS_DEBUGGABLE;
}
/**
@@ -134,7 +122,7 @@ public class LatencyTracker {
* @param action The action to start. One of the ACTION_* values.
*/
public void onActionStart(int action) {
- if (!mEnabled) {
+ if (!isEnabled()) {
return;
}
Trace.asyncTraceBegin(Trace.TRACE_TAG_APP, NAMES[action], 0);
@@ -147,7 +135,7 @@ public class LatencyTracker {
* @param action The action to end. One of the ACTION_* values.
*/
public void onActionEnd(int action) {
- if (!mEnabled) {
+ if (!isEnabled()) {
return;
}
long endRtc = SystemClock.elapsedRealtime();
@@ -169,5 +157,7 @@ public class LatencyTracker {
public static void logAction(int action, int duration) {
Log.i(TAG, "action=" + action + " latency=" + duration);
EventLog.writeEvent(EventLogTags.SYSUI_LATENCY, action, duration);
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.UI_ACTION_LATENCY_REPORTED, STATSD_ACTION[action], duration);
}
}
diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp
index 586b26ef328f..cbce38e12d25 100644
--- a/core/jni/android_view_KeyCharacterMap.cpp
+++ b/core/jni/android_view_KeyCharacterMap.cpp
@@ -1,18 +1,18 @@
/*
* Copyright 2006, 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
+ * 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
+ * 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
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
* limitations under the License.
-*/
+ */
#include <android_runtime/AndroidRuntime.h>
@@ -47,9 +47,8 @@ static struct {
class NativeKeyCharacterMap {
public:
- NativeKeyCharacterMap(int32_t deviceId, const sp<KeyCharacterMap>& map) :
- mDeviceId(deviceId), mMap(map) {
- }
+ NativeKeyCharacterMap(int32_t deviceId, std::shared_ptr<KeyCharacterMap> map)
+ : mDeviceId(deviceId), mMap(std::move(map)) {}
~NativeKeyCharacterMap() {
}
@@ -58,26 +57,22 @@ public:
return mDeviceId;
}
- inline const sp<KeyCharacterMap>& getMap() const {
- return mMap;
- }
+ inline const std::shared_ptr<KeyCharacterMap> getMap() const { return mMap; }
private:
int32_t mDeviceId;
- sp<KeyCharacterMap> mMap;
+ std::shared_ptr<KeyCharacterMap> mMap;
};
-
jobject android_view_KeyCharacterMap_create(JNIEnv* env, int32_t deviceId,
- const sp<KeyCharacterMap>& kcm) {
- NativeKeyCharacterMap* map = new NativeKeyCharacterMap(deviceId,
- kcm.get() ? kcm : KeyCharacterMap::empty());
- if (!map) {
- return NULL;
+ const std::shared_ptr<KeyCharacterMap> kcm) {
+ NativeKeyCharacterMap* nativeMap = new NativeKeyCharacterMap(deviceId, kcm);
+ if (!nativeMap) {
+ return nullptr;
}
return env->NewObject(gKeyCharacterMapClassInfo.clazz, gKeyCharacterMapClassInfo.ctor,
- reinterpret_cast<jlong>(map));
+ reinterpret_cast<jlong>(nativeMap));
}
static jlong nativeReadFromParcel(JNIEnv *env, jobject clazz, jobject parcelObj) {
@@ -91,7 +86,7 @@ static jlong nativeReadFromParcel(JNIEnv *env, jobject clazz, jobject parcelObj)
return 0;
}
- sp<KeyCharacterMap> kcm = KeyCharacterMap::readFromParcel(parcel);
+ std::shared_ptr<KeyCharacterMap> kcm = KeyCharacterMap::readFromParcel(parcel);
if (!kcm.get()) {
return 0;
}
@@ -102,6 +97,9 @@ static jlong nativeReadFromParcel(JNIEnv *env, jobject clazz, jobject parcelObj)
static void nativeWriteToParcel(JNIEnv* env, jobject clazz, jlong ptr, jobject parcelObj) {
NativeKeyCharacterMap* map = reinterpret_cast<NativeKeyCharacterMap*>(ptr);
+ if (!map->getMap()) {
+ return;
+ }
Parcel* parcel = parcelForJavaObject(env, parcelObj);
if (parcel) {
parcel->writeInt32(map->getDeviceId());
@@ -150,9 +148,8 @@ static jchar nativeGetMatch(JNIEnv *env, jobject clazz, jlong ptr, jint keyCode,
return 0;
}
- char16_t result = map->getMap()->getMatch(
- keyCode, reinterpret_cast<char16_t*>(chars), size_t(numChars),
- metaState);
+ char16_t result = map->getMap()->getMatch(keyCode, reinterpret_cast<char16_t*>(chars),
+ size_t(numChars), metaState);
env->ReleasePrimitiveArrayCritical(charsArray, chars, JNI_ABORT);
return result;
@@ -180,8 +177,7 @@ static jobjectArray nativeGetEvents(JNIEnv *env, jobject clazz, jlong ptr,
Vector<KeyEvent> events;
jobjectArray result = NULL;
- if (map->getMap()->getEvents(map->getDeviceId(),
- reinterpret_cast<char16_t*>(chars),
+ if (map->getMap()->getEvents(map->getDeviceId(), reinterpret_cast<char16_t*>(chars),
size_t(numChars), events)) {
result = env->NewObjectArray(jsize(events.size()), gKeyEventClassInfo.clazz, NULL);
if (result) {
diff --git a/core/jni/android_view_KeyCharacterMap.h b/core/jni/android_view_KeyCharacterMap.h
index e8465c2a33e3..be0335380f87 100644
--- a/core/jni/android_view_KeyCharacterMap.h
+++ b/core/jni/android_view_KeyCharacterMap.h
@@ -25,7 +25,7 @@ namespace android {
/* Creates a KeyCharacterMap object from the given information. */
extern jobject android_view_KeyCharacterMap_create(JNIEnv* env, int32_t deviceId,
- const sp<KeyCharacterMap>& map);
+ const std::shared_ptr<KeyCharacterMap> kcm);
} // namespace android
diff --git a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
index 7480a200ee4e..ece5037de15f 100644
--- a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
@@ -23,8 +23,10 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.only;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.os.Handler;
import android.view.FrameMetrics;
@@ -66,6 +68,9 @@ public class FrameTrackerTest {
Handler handler = mRule.getActivity().getMainThreadHandler();
mWrapper = Mockito.spy(new FrameMetricsWrapper());
+ // For simplicity - provide current timestamp anytime mWrapper asked for VSYNC_TIMESTAMP
+ when(mWrapper.getMetric(FrameMetrics.VSYNC_TIMESTAMP))
+ .then(unusedInvocation -> System.nanoTime());
mRenderer = Mockito.spy(new ThreadedRendererWrapper(view.getThreadedRenderer()));
doNothing().when(mRenderer).addObserver(any());
doNothing().when(mRenderer).removeObserver(any());
@@ -76,55 +81,104 @@ public class FrameTrackerTest {
}
@Test
- public void testIsJankyFrame() {
- // We skip the first frame.
- doReturn(1L).when(mWrapper).getMetric(FrameMetrics.FIRST_DRAW_FRAME);
- doReturn(TimeUnit.MILLISECONDS.toNanos(20L))
- .when(mWrapper).getMetric(FrameMetrics.TOTAL_DURATION);
- assertThat(mTracker.isJankyFrame(mWrapper)).isFalse();
+ public void testIgnoresSecondBegin() {
+ // Observer should be only added once in continuous calls.
+ mTracker.begin();
+ mTracker.begin();
+ verify(mRenderer, only()).addObserver(any());
+ }
- // Should exceed the criteria.
- doReturn(0L).when(mWrapper).getMetric(FrameMetrics.FIRST_DRAW_FRAME);
- doReturn(TimeUnit.MILLISECONDS.toNanos(20L))
- .when(mWrapper).getMetric(FrameMetrics.TOTAL_DURATION);
- assertThat(mTracker.isJankyFrame(mWrapper)).isTrue();
+ @Test
+ public void testOnlyFirstFrameOverThreshold() {
+ // Just provide current timestamp anytime mWrapper asked for VSYNC_TIMESTAMP
+ when(mWrapper.getMetric(FrameMetrics.VSYNC_TIMESTAMP))
+ .then(unusedInvocation -> System.nanoTime());
- // Should be safe.
- doReturn(TimeUnit.MILLISECONDS.toNanos(10L))
- .when(mWrapper).getMetric(FrameMetrics.TOTAL_DURATION);
- assertThat(mTracker.isJankyFrame(mWrapper)).isFalse();
+ mTracker.begin();
+ verify(mRenderer, only()).addObserver(any());
+
+ // send first frame with a long duration - should not be taken into account
+ setupFirstFrameMockWithDuration(100);
+ mTracker.onFrameMetricsAvailable(0);
+
+ // send another frame with a short duration - should not be considered janky
+ setupOtherFrameMockWithDuration(5);
+ mTracker.onFrameMetricsAvailable(0);
+
+ // end the trace session, the last janky frame is after the end() so is discarded.
+ mTracker.end();
+ setupOtherFrameMockWithDuration(500);
+ mTracker.onFrameMetricsAvailable(0);
+
+ verify(mRenderer).removeObserver(any());
+ verify(mTracker, never()).triggerPerfetto();
}
@Test
- public void testBeginEnd() {
- // assert the initial values
- assertThat(mTracker.mBeginTime).isEqualTo(FrameTracker.UNKNOWN_TIMESTAMP);
- assertThat(mTracker.mEndTime).isEqualTo(FrameTracker.UNKNOWN_TIMESTAMP);
-
- // Observer should be only added once in continuous calls.
+ public void testOtherFrameOverThreshold() {
mTracker.begin();
+ verify(mRenderer, only()).addObserver(any());
+
+ // send first frame - not janky
+ setupFirstFrameMockWithDuration(4);
+ mTracker.onFrameMetricsAvailable(0);
+
+ // send another frame - should be considered janky
+ setupOtherFrameMockWithDuration(40);
+ mTracker.onFrameMetricsAvailable(0);
+
+ // end the trace session
+ mTracker.end();
+ setupOtherFrameMockWithDuration(5);
+ mTracker.onFrameMetricsAvailable(0);
+
+ verify(mRenderer).removeObserver(any());
+
+ // We detected a janky frame - trigger Perfetto
+ verify(mTracker).triggerPerfetto();
+ }
+
+ @Test
+ public void testLastFrameOverThresholdBeforeEnd() {
mTracker.begin();
verify(mRenderer, only()).addObserver(any());
- // assert the values after begin call.
- assertThat(mTracker.mBeginTime).isNotEqualTo(FrameTracker.UNKNOWN_TIMESTAMP);
- assertThat(mTracker.mEndTime).isEqualTo(FrameTracker.UNKNOWN_TIMESTAMP);
+ // send first frame - not janky
+ setupFirstFrameMockWithDuration(4);
+ mTracker.onFrameMetricsAvailable(0);
- // simulate the callback during trace session
- // assert the isJankyFrame should be invoked as well.
- doReturn(System.nanoTime()).when(mWrapper).getMetric(FrameMetrics.VSYNC_TIMESTAMP);
- doReturn(true).when(mTracker).isJankyFrame(any());
+ // send another frame - not janky
+ setupOtherFrameMockWithDuration(4);
mTracker.onFrameMetricsAvailable(0);
- verify(mTracker).isJankyFrame(any());
- // end the trace session, simulate a callback came after the end call.
- // assert the end time should be set, the observer should be removed.
- // triggerPerfetto should be invoked as well.
+ // end the trace session, simulate one more valid callback came after the end call.
+ when(mWrapper.getMetric(FrameMetrics.VSYNC_TIMESTAMP))
+ .thenReturn(System.nanoTime());
+ setupOtherFrameMockWithDuration(50);
mTracker.end();
- doReturn(System.nanoTime()).when(mWrapper).getMetric(FrameMetrics.VSYNC_TIMESTAMP);
- assertThat(mTracker.mEndTime).isNotEqualTo(FrameTracker.UNKNOWN_TIMESTAMP);
mTracker.onFrameMetricsAvailable(0);
+
+ // One more callback with VSYNC after the end() timestamp.
+ when(mWrapper.getMetric(FrameMetrics.VSYNC_TIMESTAMP))
+ .thenReturn(System.nanoTime());
+ setupOtherFrameMockWithDuration(5);
+ mTracker.onFrameMetricsAvailable(0);
+
verify(mRenderer).removeObserver(any());
+
+ // We detected a janky frame - trigger Perfetto
verify(mTracker).triggerPerfetto();
}
+
+ private void setupFirstFrameMockWithDuration(long durationMillis) {
+ doReturn(1L).when(mWrapper).getMetric(FrameMetrics.FIRST_DRAW_FRAME);
+ doReturn(TimeUnit.MILLISECONDS.toNanos(durationMillis))
+ .when(mWrapper).getMetric(FrameMetrics.TOTAL_DURATION);
+ }
+
+ private void setupOtherFrameMockWithDuration(long durationMillis) {
+ doReturn(0L).when(mWrapper).getMetric(FrameMetrics.FIRST_DRAW_FRAME);
+ doReturn(TimeUnit.MILLISECONDS.toNanos(durationMillis))
+ .when(mWrapper).getMetric(FrameMetrics.TOTAL_DURATION);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
index 12749fd8fce2..357f777e1270 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/FlingAnimationUtils.java
@@ -11,10 +11,10 @@
* 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
+ * limitations under the License.
*/
-package com.android.systemui.statusbar;
+package com.android.wm.shell.animation;
import android.animation.Animator;
import android.util.DisplayMetrics;
@@ -23,11 +23,6 @@ import android.view.ViewPropertyAnimator;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
-import com.android.systemui.Interpolators;
-import com.android.systemui.statusbar.notification.NotificationUtils;
-
-import javax.inject.Inject;
-
/**
* Utility class to calculate general fling animation when the finger is released.
*/
@@ -63,9 +58,9 @@ public class FlingAnimationUtils {
/**
* @param maxLengthSeconds the longest duration an animation can become in seconds
- * @param speedUpFactor a factor from 0 to 1 how much the slow down should be shifted towards
- * the end of the animation. 0 means it's at the beginning and no
- * acceleration will take place.
+ * @param speedUpFactor a factor from 0 to 1 how much the slow down should be shifted towards
+ * the end of the animation. 0 means it's at the beginning and no
+ * acceleration will take place.
*/
public FlingAnimationUtils(DisplayMetrics displayMetrics, float maxLengthSeconds,
float speedUpFactor) {
@@ -74,19 +69,19 @@ public class FlingAnimationUtils {
/**
* @param maxLengthSeconds the longest duration an animation can become in seconds
- * @param speedUpFactor a factor from 0 to 1 how much the slow down should be shifted towards
- * the end of the animation. 0 means it's at the beginning and no
- * acceleration will take place.
- * @param x2 the x value to take for the second point of the bezier spline. If a value below 0
- * is provided, the value is automatically calculated.
- * @param y2 the y value to take for the second point of the bezier spline
+ * @param speedUpFactor a factor from 0 to 1 how much the slow down should be shifted towards
+ * the end of the animation. 0 means it's at the beginning and no
+ * acceleration will take place.
+ * @param x2 the x value to take for the second point of the bezier spline. If a
+ * value below 0 is provided, the value is automatically calculated.
+ * @param y2 the y value to take for the second point of the bezier spline
*/
public FlingAnimationUtils(DisplayMetrics displayMetrics, float maxLengthSeconds,
float speedUpFactor, float x2, float y2) {
mMaxLengthSeconds = maxLengthSeconds;
mSpeedUpFactor = speedUpFactor;
if (x2 < 0) {
- mLinearOutSlowInX2 = NotificationUtils.interpolate(LINEAR_OUT_SLOW_IN_X2,
+ mLinearOutSlowInX2 = interpolate(LINEAR_OUT_SLOW_IN_X2,
LINEAR_OUT_SLOW_IN_X2_MAX,
mSpeedUpFactor);
} else {
@@ -102,10 +97,10 @@ public class FlingAnimationUtils {
* Applies the interpolator and length to the animator, such that the fling animation is
* consistent with the finger motion.
*
- * @param animator the animator to apply
+ * @param animator the animator to apply
* @param currValue the current value
- * @param endValue the end value of the animator
- * @param velocity the current velocity of the motion
+ * @param endValue the end value of the animator
+ * @param velocity the current velocity of the motion
*/
public void apply(Animator animator, float currValue, float endValue, float velocity) {
apply(animator, currValue, endValue, velocity, Math.abs(endValue - currValue));
@@ -115,10 +110,10 @@ public class FlingAnimationUtils {
* Applies the interpolator and length to the animator, such that the fling animation is
* consistent with the finger motion.
*
- * @param animator the animator to apply
+ * @param animator the animator to apply
* @param currValue the current value
- * @param endValue the end value of the animator
- * @param velocity the current velocity of the motion
+ * @param endValue the end value of the animator
+ * @param velocity the current velocity of the motion
*/
public void apply(ViewPropertyAnimator animator, float currValue, float endValue,
float velocity) {
@@ -129,10 +124,10 @@ public class FlingAnimationUtils {
* Applies the interpolator and length to the animator, such that the fling animation is
* consistent with the finger motion.
*
- * @param animator the animator to apply
- * @param currValue the current value
- * @param endValue the end value of the animator
- * @param velocity the current velocity of the motion
+ * @param animator the animator to apply
+ * @param currValue the current value
+ * @param endValue the end value of the animator
+ * @param velocity the current velocity of the motion
* @param maxDistance the maximum distance for this interaction; the maximum animation length
* gets multiplied by the ratio between the actual distance and this value
*/
@@ -140,18 +135,18 @@ public class FlingAnimationUtils {
float maxDistance) {
AnimatorProperties properties = getProperties(currValue, endValue, velocity,
maxDistance);
- animator.setDuration(properties.duration);
- animator.setInterpolator(properties.interpolator);
+ animator.setDuration(properties.mDuration);
+ animator.setInterpolator(properties.mInterpolator);
}
/**
* Applies the interpolator and length to the animator, such that the fling animation is
* consistent with the finger motion.
*
- * @param animator the animator to apply
- * @param currValue the current value
- * @param endValue the end value of the animator
- * @param velocity the current velocity of the motion
+ * @param animator the animator to apply
+ * @param currValue the current value
+ * @param endValue the end value of the animator
+ * @param velocity the current velocity of the motion
* @param maxDistance the maximum distance for this interaction; the maximum animation length
* gets multiplied by the ratio between the actual distance and this value
*/
@@ -159,8 +154,8 @@ public class FlingAnimationUtils {
float velocity, float maxDistance) {
AnimatorProperties properties = getProperties(currValue, endValue, velocity,
maxDistance);
- animator.setDuration(properties.duration);
- animator.setInterpolator(properties.interpolator);
+ animator.setDuration(properties.mDuration);
+ animator.setInterpolator(properties.mInterpolator);
}
private AnimatorProperties getProperties(float currValue,
@@ -171,28 +166,28 @@ public class FlingAnimationUtils {
float velAbs = Math.abs(velocity);
float velocityFactor = mSpeedUpFactor == 0.0f
? 1.0f : Math.min(velAbs / HIGH_VELOCITY_DP_PER_SECOND, 1.0f);
- float startGradient = NotificationUtils.interpolate(LINEAR_OUT_SLOW_IN_START_GRADIENT,
+ float startGradient = interpolate(LINEAR_OUT_SLOW_IN_START_GRADIENT,
mY2 / mLinearOutSlowInX2, velocityFactor);
float durationSeconds = startGradient * diff / velAbs;
Interpolator slowInInterpolator = getInterpolator(startGradient, velocityFactor);
if (durationSeconds <= maxLengthSeconds) {
- mAnimatorProperties.interpolator = slowInInterpolator;
+ mAnimatorProperties.mInterpolator = slowInInterpolator;
} else if (velAbs >= mMinVelocityPxPerSecond) {
// Cross fade between fast-out-slow-in and linear interpolator with current velocity.
durationSeconds = maxLengthSeconds;
- VelocityInterpolator velocityInterpolator
- = new VelocityInterpolator(durationSeconds, velAbs, diff);
+ VelocityInterpolator velocityInterpolator = new VelocityInterpolator(
+ durationSeconds, velAbs, diff);
InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator(
velocityInterpolator, slowInInterpolator, Interpolators.LINEAR_OUT_SLOW_IN);
- mAnimatorProperties.interpolator = superInterpolator;
+ mAnimatorProperties.mInterpolator = superInterpolator;
} else {
// Just use a normal interpolator which doesn't take the velocity into account.
durationSeconds = maxLengthSeconds;
- mAnimatorProperties.interpolator = Interpolators.FAST_OUT_SLOW_IN;
+ mAnimatorProperties.mInterpolator = Interpolators.FAST_OUT_SLOW_IN;
}
- mAnimatorProperties.duration = (long) (durationSeconds * 1000);
+ mAnimatorProperties.mDuration = (long) (durationSeconds * 1000);
return mAnimatorProperties;
}
@@ -225,10 +220,10 @@ public class FlingAnimationUtils {
* consistent with the finger motion for the case when the animation is making something
* disappear.
*
- * @param animator the animator to apply
- * @param currValue the current value
- * @param endValue the end value of the animator
- * @param velocity the current velocity of the motion
+ * @param animator the animator to apply
+ * @param currValue the current value
+ * @param endValue the end value of the animator
+ * @param velocity the current velocity of the motion
* @param maxDistance the maximum distance for this interaction; the maximum animation length
* gets multiplied by the ratio between the actual distance and this value
*/
@@ -236,8 +231,8 @@ public class FlingAnimationUtils {
float velocity, float maxDistance) {
AnimatorProperties properties = getDismissingProperties(currValue, endValue, velocity,
maxDistance);
- animator.setDuration(properties.duration);
- animator.setInterpolator(properties.interpolator);
+ animator.setDuration(properties.mDuration);
+ animator.setInterpolator(properties.mInterpolator);
}
/**
@@ -245,10 +240,10 @@ public class FlingAnimationUtils {
* consistent with the finger motion for the case when the animation is making something
* disappear.
*
- * @param animator the animator to apply
- * @param currValue the current value
- * @param endValue the end value of the animator
- * @param velocity the current velocity of the motion
+ * @param animator the animator to apply
+ * @param currValue the current value
+ * @param endValue the end value of the animator
+ * @param velocity the current velocity of the motion
* @param maxDistance the maximum distance for this interaction; the maximum animation length
* gets multiplied by the ratio between the actual distance and this value
*/
@@ -256,8 +251,8 @@ public class FlingAnimationUtils {
float velocity, float maxDistance) {
AnimatorProperties properties = getDismissingProperties(currValue, endValue, velocity,
maxDistance);
- animator.setDuration(properties.duration);
- animator.setInterpolator(properties.interpolator);
+ animator.setDuration(properties.mDuration);
+ animator.setInterpolator(properties.mInterpolator);
}
private AnimatorProperties getDismissingProperties(float currValue, float endValue,
@@ -272,24 +267,24 @@ public class FlingAnimationUtils {
Interpolator mLinearOutFasterIn = new PathInterpolator(0, 0, LINEAR_OUT_FASTER_IN_X2, y2);
float durationSeconds = startGradient * diff / velAbs;
if (durationSeconds <= maxLengthSeconds) {
- mAnimatorProperties.interpolator = mLinearOutFasterIn;
+ mAnimatorProperties.mInterpolator = mLinearOutFasterIn;
} else if (velAbs >= mMinVelocityPxPerSecond) {
// Cross fade between linear-out-faster-in and linear interpolator with current
// velocity.
durationSeconds = maxLengthSeconds;
- VelocityInterpolator velocityInterpolator
- = new VelocityInterpolator(durationSeconds, velAbs, diff);
+ VelocityInterpolator velocityInterpolator = new VelocityInterpolator(
+ durationSeconds, velAbs, diff);
InterpolatorInterpolator superInterpolator = new InterpolatorInterpolator(
velocityInterpolator, mLinearOutFasterIn, Interpolators.LINEAR_OUT_SLOW_IN);
- mAnimatorProperties.interpolator = superInterpolator;
+ mAnimatorProperties.mInterpolator = superInterpolator;
} else {
// Just use a normal interpolator which doesn't take the velocity into account.
durationSeconds = maxLengthSeconds;
- mAnimatorProperties.interpolator = Interpolators.FAST_OUT_LINEAR_IN;
+ mAnimatorProperties.mInterpolator = Interpolators.FAST_OUT_LINEAR_IN;
}
- mAnimatorProperties.duration = (long) (durationSeconds * 1000);
+ mAnimatorProperties.mDuration = (long) (durationSeconds * 1000);
return mAnimatorProperties;
}
@@ -361,10 +356,11 @@ public class FlingAnimationUtils {
}
private static class AnimatorProperties {
- Interpolator interpolator;
- long duration;
+ Interpolator mInterpolator;
+ long mDuration;
}
+ /** Builder for {@link #FlingAnimationUtils}. */
public static class Builder {
private final DisplayMetrics mDisplayMetrics;
float mMaxLengthSeconds;
@@ -372,32 +368,39 @@ public class FlingAnimationUtils {
float mX2;
float mY2;
- @Inject
public Builder(DisplayMetrics displayMetrics) {
mDisplayMetrics = displayMetrics;
reset();
}
+ /** Sets the longest duration an animation can become in seconds. */
public Builder setMaxLengthSeconds(float maxLengthSeconds) {
mMaxLengthSeconds = maxLengthSeconds;
return this;
}
+ /**
+ * Sets the factor for how much the slow down should be shifted towards the end of the
+ * animation.
+ */
public Builder setSpeedUpFactor(float speedUpFactor) {
mSpeedUpFactor = speedUpFactor;
return this;
}
+ /** Sets the x value to take for the second point of the bezier spline. */
public Builder setX2(float x2) {
mX2 = x2;
return this;
}
+ /** Sets the y value to take for the second point of the bezier spline. */
public Builder setY2(float y2) {
mY2 = y2;
return this;
}
+ /** Resets all parameters of the builder. */
public Builder reset() {
mMaxLengthSeconds = 0;
mSpeedUpFactor = 0.0f;
@@ -407,9 +410,14 @@ public class FlingAnimationUtils {
return this;
}
+ /** Builds {@link #FlingAnimationUtils}. */
public FlingAnimationUtils build() {
return new FlingAnimationUtils(mDisplayMetrics, mMaxLengthSeconds, mSpeedUpFactor,
mX2, mY2);
}
}
+
+ private static float interpolate(float start, float end, float amount) {
+ return start * (1.0f - amount) + end * amount;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
new file mode 100644
index 000000000000..b794b91568fc
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
@@ -0,0 +1,45 @@
+/*
+ * 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.animation;
+
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+
+/**
+ * Common interpolators used in wm shell library.
+ */
+public class Interpolators {
+ /**
+ * Interpolator for fast out linear in animation.
+ */
+ public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
+
+ /**
+ * Interpolator for fast out slow in animation.
+ */
+ public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+
+ /**
+ * Interpolator for linear out slow in animation.
+ */
+ public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
+
+ /**
+ * Interpolator to be used when animating a move based on a click. Pair with enough duration.
+ */
+ public static final Interpolator TOUCH_RESPONSE = new PathInterpolator(0.3f, 0f, 0.1f, 1f);
+}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 7518496287a8..1e9cf2c24c7c 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -166,26 +166,3 @@ cc_library_shared {
],
}
-cc_library_shared {
- name: "libmediatranscodemanager_jni",
- srcs: [
- "android_media_MediaTranscodeManager.cpp",
- ],
-
- shared_libs: [
- "libandroid_runtime",
- "libcutils",
- "liblog",
- "libmedia",
- ],
-
- export_include_dirs: ["."],
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wunused",
- "-Wunreachable-code",
- ],
-}
diff --git a/media/jni/android_media_MediaTranscodeManager.cpp b/media/jni/android_media_MediaTranscodeManager.cpp
deleted file mode 100644
index 6695f8511116..000000000000
--- a/media/jni/android_media_MediaTranscodeManager.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright 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.
- */
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaTranscodeManager_JNI"
-
-#include "android_runtime/AndroidRuntime.h"
-#include "jni.h"
-
-#include <nativehelper/JNIHelp.h>
-#include <utils/Log.h>
-
-namespace {
-
-// NOTE: Keep these enums in sync with their equivalents in MediaTranscodeManager.java.
-enum {
- ID_INVALID = -1
-};
-
-enum {
- EVENT_JOB_STARTED = 1,
- EVENT_JOB_PROGRESSED = 2,
- EVENT_JOB_FINISHED = 3,
-};
-
-enum {
- RESULT_NONE = 1,
- RESULT_SUCCESS = 2,
- RESULT_ERROR = 3,
- RESULT_CANCELED = 4,
-};
-
-struct {
- jmethodID postEventFromNative;
-} gMediaTranscodeManagerClassInfo;
-
-using namespace android;
-
-void android_media_MediaTranscodeManager_native_init(JNIEnv *env, jclass clazz) {
- ALOGV("android_media_MediaTranscodeManager_native_init");
-
- gMediaTranscodeManagerClassInfo.postEventFromNative = env->GetMethodID(
- clazz, "postEventFromNative", "(IJI)V");
- LOG_ALWAYS_FATAL_IF(gMediaTranscodeManagerClassInfo.postEventFromNative == NULL,
- "can't find android/media/MediaTranscodeManager.postEventFromNative");
-}
-
-jlong android_media_MediaTranscodeManager_requestUniqueJobID(
- JNIEnv *env __unused, jobject thiz __unused) {
- ALOGV("android_media_MediaTranscodeManager_reserveUniqueJobID");
- static std::atomic_int32_t sJobIDCounter{0};
- jlong id = (jlong)++sJobIDCounter;
- return id;
-}
-
-jboolean android_media_MediaTranscodeManager_enqueueTranscodingRequest(
- JNIEnv *env, jobject thiz, jlong id, jobject request, jobject context __unused) {
- ALOGV("android_media_MediaTranscodeManager_enqueueTranscodingRequest");
- if (!request) {
- return ID_INVALID;
- }
-
- env->CallVoidMethod(thiz, gMediaTranscodeManagerClassInfo.postEventFromNative,
- EVENT_JOB_FINISHED, id, RESULT_ERROR);
- return true;
-}
-
-void android_media_MediaTranscodeManager_cancelTranscodingRequest(
- JNIEnv *env __unused, jobject thiz __unused, jlong jobID __unused) {
- ALOGV("android_media_MediaTranscodeManager_cancelTranscodingRequest");
-}
-
-const JNINativeMethod gMethods[] = {
- { "native_init", "()V",
- (void *)android_media_MediaTranscodeManager_native_init },
- { "native_requestUniqueJobID", "()J",
- (void *)android_media_MediaTranscodeManager_requestUniqueJobID },
- { "native_enqueueTranscodingRequest",
- "(JLandroid/media/MediaTranscodeManager$TranscodingRequest;Landroid/content/Context;)Z",
- (void *)android_media_MediaTranscodeManager_enqueueTranscodingRequest },
- { "native_cancelTranscodingRequest", "(J)V",
- (void *)android_media_MediaTranscodeManager_cancelTranscodingRequest },
-};
-
-} // namespace anonymous
-
-int register_android_media_MediaTranscodeManager(JNIEnv *env) {
- return AndroidRuntime::registerNativeMethods(env,
- "android/media/MediaTranscodeManager", gMethods, NELEM(gMethods));
-}
-
-jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
-{
- JNIEnv* env = NULL;
- jint result = -1;
-
- if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
- ALOGE("ERROR: GetEnv failed\n");
- return result;
- }
- assert(env != NULL);
-
- if (register_android_media_MediaTranscodeManager(env) < 0) {
- ALOGE("ERROR: MediaTranscodeManager native registration failed");
- goto bail;
- }
-
- /* success -- return valid version number */
- result = JNI_VERSION_1_4;
-
-bail:
- return result;
-}
diff --git a/packages/CarSystemUI/res/drawable/car_ic_apps.xml b/packages/CarSystemUI/res/drawable/car_ic_apps.xml
index a8d8a2f241f6..e028a0ed45c9 100644
--- a/packages/CarSystemUI/res/drawable/car_ic_apps.xml
+++ b/packages/CarSystemUI/res/drawable/car_ic_apps.xml
@@ -15,11 +15,11 @@
~ limitations under the License
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"
android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
-<path
- android:pathData="M7.33333333 14.6666667L14.6666667 14.6666667L14.6666667 7.33333333L7.33333333 7.33333333L7.33333333 14.6666667ZM18.3333333 36.6666667L25.6666667 36.6666667L25.6666667 29.3333333L18.3333333 29.3333333L18.3333333 36.6666667ZM7.33333333 36.6666667L14.6666667 36.6666667L14.6666667 29.3333333L7.33333333 29.3333333L7.33333333 36.6666667ZM7.33333333 25.6666667L14.6666667 25.6666667L14.6666667 18.3333333L7.33333333 18.3333333L7.33333333 25.6666667ZM18.3333333 25.6666667L25.6666667 25.6666667L25.6666667 18.3333333L18.3333333 18.3333333L18.3333333 25.6666667ZM29.3333333 7.33333333L29.3333333 14.6666667L36.6666667 14.6666667L36.6666667 7.33333333L29.3333333 7.33333333ZM18.3333333 14.6666667L25.6666667 14.6666667L25.6666667 7.33333333L18.3333333 7.33333333L18.3333333 14.6666667ZM29.3333333 25.6666667L36.6666667 25.6666667L36.6666667 18.3333333L29.3333333 18.3333333L29.3333333 25.6666667ZM29.3333333 36.6666667L36.6666667 36.6666667L36.6666667 29.3333333L29.3333333 29.3333333L29.3333333 36.6666667Z"
- android:fillColor="@color/car_nav_icon_fill_color" />
+ android:viewportHeight="44">
+ <path
+ android:pathData="M7.33333333 14.6666667L14.6666667 14.6666667L14.6666667 7.33333333L7.33333333 7.33333333L7.33333333 14.6666667ZM18.3333333 36.6666667L25.6666667 36.6666667L25.6666667 29.3333333L18.3333333 29.3333333L18.3333333 36.6666667ZM7.33333333 36.6666667L14.6666667 36.6666667L14.6666667 29.3333333L7.33333333 29.3333333L7.33333333 36.6666667ZM7.33333333 25.6666667L14.6666667 25.6666667L14.6666667 18.3333333L7.33333333 18.3333333L7.33333333 25.6666667ZM18.3333333 25.6666667L25.6666667 25.6666667L25.6666667 18.3333333L18.3333333 18.3333333L18.3333333 25.6666667ZM29.3333333 7.33333333L29.3333333 14.6666667L36.6666667 14.6666667L36.6666667 7.33333333L29.3333333 7.33333333ZM18.3333333 14.6666667L25.6666667 14.6666667L25.6666667 7.33333333L18.3333333 7.33333333L18.3333333 14.6666667ZM29.3333333 25.6666667L36.6666667 25.6666667L36.6666667 18.3333333L29.3333333 18.3333333L29.3333333 25.6666667ZM29.3333333 36.6666667L36.6666667 36.6666667L36.6666667 29.3333333L29.3333333 29.3333333L29.3333333 36.6666667Z"
+ android:fillColor="@color/car_nav_icon_fill_color" />
</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_apps_selected.xml b/packages/CarSystemUI/res/drawable/car_ic_apps_selected.xml
index 2a4e91aa3cd9..9504e61e53e4 100644
--- a/packages/CarSystemUI/res/drawable/car_ic_apps_selected.xml
+++ b/packages/CarSystemUI/res/drawable/car_ic_apps_selected.xml
@@ -15,10 +15,10 @@
~ limitations under the License
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"
android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
+ android:viewportHeight="44">
<path
android:pathData="M7.33333333 14.6666667L14.6666667 14.6666667L14.6666667 7.33333333L7.33333333 7.33333333L7.33333333 14.6666667ZM18.3333333 36.6666667L25.6666667 36.6666667L25.6666667 29.3333333L18.3333333 29.3333333L18.3333333 36.6666667ZM7.33333333 36.6666667L14.6666667 36.6666667L14.6666667 29.3333333L7.33333333 29.3333333L7.33333333 36.6666667ZM7.33333333 25.6666667L14.6666667 25.6666667L14.6666667 18.3333333L7.33333333 18.3333333L7.33333333 25.6666667ZM18.3333333 25.6666667L25.6666667 25.6666667L25.6666667 18.3333333L18.3333333 18.3333333L18.3333333 25.6666667ZM29.3333333 7.33333333L29.3333333 14.6666667L36.6666667 14.6666667L36.6666667 7.33333333L29.3333333 7.33333333ZM18.3333333 14.6666667L25.6666667 14.6666667L25.6666667 7.33333333L18.3333333 7.33333333L18.3333333 14.6666667ZM29.3333333 25.6666667L36.6666667 25.6666667L36.6666667 18.3333333L29.3333333 18.3333333L29.3333333 25.6666667ZM29.3333333 36.6666667L36.6666667 36.6666667L36.6666667 29.3333333L29.3333333 29.3333333L29.3333333 36.6666667Z"
android:fillColor="@color/car_nav_icon_fill_color_selected" />
diff --git a/packages/CarSystemUI/res/drawable/car_ic_home.xml b/packages/CarSystemUI/res/drawable/car_ic_home.xml
new file mode 100644
index 000000000000..c78f0edd5594
--- /dev/null
+++ b/packages/CarSystemUI/res/drawable/car_ic_home.xml
@@ -0,0 +1,25 @@
+<?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="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"
+ android:fillColor="@color/car_nav_icon_fill_color" />
+</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_home_selected.xml b/packages/CarSystemUI/res/drawable/car_ic_home_selected.xml
new file mode 100644
index 000000000000..16192df86676
--- /dev/null
+++ b/packages/CarSystemUI/res/drawable/car_ic_home_selected.xml
@@ -0,0 +1,25 @@
+<?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="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"
+ android:fillColor="@color/car_nav_icon_fill_color_selected" />
+</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_hvac.xml b/packages/CarSystemUI/res/drawable/car_ic_hvac.xml
index bdc44b38a176..55c968eacc4d 100644
--- a/packages/CarSystemUI/res/drawable/car_ic_hvac.xml
+++ b/packages/CarSystemUI/res/drawable/car_ic_hvac.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018 The Android Open Source Project
@@ -14,38 +15,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="37dp"
- android:height="31dp"
- android:viewportWidth="37"
- android:viewportHeight="31">
-
- <group
- android:translateX="-4.000000"
- android:translateY="-6.000000">
- <group
- android:translateX="5.000000"
- android:translateY="5.000000">
- <path
- android:fillType="evenOdd"
- android:strokeColor="#FAFAFA"
- android:strokeWidth="3.5"
- android:pathData="M0.320769938,6.07518051 C6.46754647,1.46509811 12.4222362,1.46509811
-18.1848392,6.07518051 C23.9474422,10.6852629 29.3258717,10.4931761
-34.3201276,5.49892021" />
- <path
- android:fillType="evenOdd"
- android:strokeColor="#FAFAFA"
- android:strokeWidth="3.5"
- android:pathData="M0.320769938,17.0751805 C6.46754647,12.4650981 12.4222362,12.4650981
-18.1848392,17.0751805 C23.9474422,21.6852629 29.3258717,21.4931761
-34.3201276,16.4989202" />
- <path
- android:fillType="evenOdd"
- android:strokeColor="#FAFAFA"
- android:strokeWidth="3.5"
- android:pathData="M0.320769938,28.0751805 C6.46754647,23.4650981 12.4222362,23.4650981
-18.1848392,28.0751805 C23.9474422,32.6852629 29.3258717,32.4931761
-34.3201276,27.4989202" />
- </group>
- </group>
-</vector> \ No newline at end of file
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M16.34,8.36l-2.29,0.82c-0.18,-0.13 -0.38,-0.25 -0.58,-0.34c0.17,-0.83 0.63,-1.58 1.36,-2.06C16.85,5.44 16.18,2 13.39,2C9,2 7.16,5.01 8.36,7.66l0.82,2.29c-0.13,0.18 -0.25,0.38 -0.34,0.58c-0.83,-0.17 -1.58,-0.63 -2.06,-1.36C5.44,7.15 2,7.82 2,10.61c0,4.4 3.01,6.24 5.66,5.03l2.29,-0.82c0.18,0.13 0.38,0.25 0.58,0.34c-0.17,0.83 -0.63,1.58 -1.36,2.06C7.15,18.56 7.82,22 10.61,22c4.4,0 6.24,-3.01 5.03,-5.66l-0.82,-2.29c0.13,-0.18 0.25,-0.38 0.34,-0.58c0.83,0.17 1.58,0.63 2.06,1.36c1.34,2.01 4.77,1.34 4.77,-1.45C22,9 18.99,7.16 16.34,8.36zM12,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5c0.83,0 1.5,0.67 1.5,1.5C13.5,12.83 12.83,13.5 12,13.5zM10.24,5.22C10.74,4.44 11.89,4 13.39,4c0.79,0 0.71,0.86 0.34,1.11c-1.22,0.81 -2,2.06 -2.25,3.44c-0.21,0.03 -0.42,0.08 -0.62,0.15l-0.68,-1.88C10,6.42 9.86,5.81 10.24,5.22zM6.83,13.82c-0.4,0.18 -1.01,0.32 -1.61,-0.06C4.44,13.26 4,12.11 4,10.61c0,-0.79 0.86,-0.71 1.11,-0.34c0.81,1.22 2.06,2 3.44,2.25c0.03,0.21 0.08,0.42 0.15,0.62L6.83,13.82zM13.76,18.78c-0.5,0.77 -1.65,1.22 -3.15,1.22c-0.79,0 -0.71,-0.86 -0.34,-1.11c1.22,-0.81 2,-2.06 2.25,-3.44c0.21,-0.03 0.42,-0.08 0.62,-0.15l0.68,1.88C14,17.58 14.14,18.18 13.76,18.78zM18.89,13.73c-0.81,-1.22 -2.06,-2 -3.44,-2.25c-0.03,-0.21 -0.08,-0.42 -0.15,-0.62l1.88,-0.68c0.4,-0.18 1.01,-0.32 1.61,0.06c0.77,0.5 1.22,1.65 1.22,3.15C20,14.19 19.14,14.11 18.89,13.73z"
+ android:fillColor="@color/car_nav_icon_fill_color" />
+</vector>
diff --git a/packages/CarSystemUI/res/drawable/car_ic_hvac_selected.xml b/packages/CarSystemUI/res/drawable/car_ic_hvac_selected.xml
new file mode 100644
index 000000000000..817b7148ecdd
--- /dev/null
+++ b/packages/CarSystemUI/res/drawable/car_ic_hvac_selected.xml
@@ -0,0 +1,25 @@
+<?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="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M16.34,8.36l-2.29,0.82c-0.18,-0.13 -0.38,-0.25 -0.58,-0.34c0.17,-0.83 0.63,-1.58 1.36,-2.06C16.85,5.44 16.18,2 13.39,2C9,2 7.16,5.01 8.36,7.66l0.82,2.29c-0.13,0.18 -0.25,0.38 -0.34,0.58c-0.83,-0.17 -1.58,-0.63 -2.06,-1.36C5.44,7.15 2,7.82 2,10.61c0,4.4 3.01,6.24 5.66,5.03l2.29,-0.82c0.18,0.13 0.38,0.25 0.58,0.34c-0.17,0.83 -0.63,1.58 -1.36,2.06C7.15,18.56 7.82,22 10.61,22c4.4,0 6.24,-3.01 5.03,-5.66l-0.82,-2.29c0.13,-0.18 0.25,-0.38 0.34,-0.58c0.83,0.17 1.58,0.63 2.06,1.36c1.34,2.01 4.77,1.34 4.77,-1.45C22,9 18.99,7.16 16.34,8.36zM12,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5c0.83,0 1.5,0.67 1.5,1.5C13.5,12.83 12.83,13.5 12,13.5zM10.24,5.22C10.74,4.44 11.89,4 13.39,4c0.79,0 0.71,0.86 0.34,1.11c-1.22,0.81 -2,2.06 -2.25,3.44c-0.21,0.03 -0.42,0.08 -0.62,0.15l-0.68,-1.88C10,6.42 9.86,5.81 10.24,5.22zM6.83,13.82c-0.4,0.18 -1.01,0.32 -1.61,-0.06C4.44,13.26 4,12.11 4,10.61c0,-0.79 0.86,-0.71 1.11,-0.34c0.81,1.22 2.06,2 3.44,2.25c0.03,0.21 0.08,0.42 0.15,0.62L6.83,13.82zM13.76,18.78c-0.5,0.77 -1.65,1.22 -3.15,1.22c-0.79,0 -0.71,-0.86 -0.34,-1.11c1.22,-0.81 2,-2.06 2.25,-3.44c0.21,-0.03 0.42,-0.08 0.62,-0.15l0.68,1.88C14,17.58 14.14,18.18 13.76,18.78zM18.89,13.73c-0.81,-1.22 -2.06,-2 -3.44,-2.25c-0.03,-0.21 -0.08,-0.42 -0.15,-0.62l1.88,-0.68c0.4,-0.18 1.01,-0.32 1.61,0.06c0.77,0.5 1.22,1.65 1.22,3.15C20,14.19 19.14,14.11 18.89,13.73z"
+ android:fillColor="@color/car_nav_icon_fill_color_selected" />
+</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/car_ic_notification.xml b/packages/CarSystemUI/res/drawable/car_ic_notification.xml
index 9d9ad0fdf9c5..aabf9161c11f 100644
--- a/packages/CarSystemUI/res/drawable/car_ic_notification.xml
+++ b/packages/CarSystemUI/res/drawable/car_ic_notification.xml
@@ -15,10 +15,10 @@
~ limitations under the License
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"
+ android:viewportWidth="44"
+ android:viewportHeight="44">
<path
android:pathData="M22 39.125C23.925 39.125 25.5 37.55 25.5 35.625L18.5 35.625C18.5 37.55 20.0575 39.125 22 39.125ZM32.5 28.625L32.5 19.875C32.5 14.5025 29.63 10.005 24.625 8.815L24.625 7.625C24.625 6.1725 23.4525 5 22 5C20.5475 5 19.375 6.1725 19.375 7.625L19.375 8.815C14.3525 10.005 11.5 14.485 11.5 19.875L11.5 28.625L8 32.125L8 33.875L36 33.875L36 32.125L32.5 28.625Z"
android:fillColor="@color/car_nav_icon_fill_color" />
diff --git a/packages/CarSystemUI/res/drawable/car_ic_user_icon.xml b/packages/CarSystemUI/res/drawable/car_ic_user_icon.xml
new file mode 100644
index 000000000000..1195d05da228
--- /dev/null
+++ b/packages/CarSystemUI/res/drawable/car_ic_user_icon.xml
@@ -0,0 +1,25 @@
+<?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="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"
+ android:viewportWidth="24"
+ 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"/>
+</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/hvac_decrease_button.xml b/packages/CarSystemUI/res/drawable/hvac_decrease_button.xml
new file mode 100644
index 000000000000..469ac91073f9
--- /dev/null
+++ b/packages/CarSystemUI/res/drawable/hvac_decrease_button.xml
@@ -0,0 +1,53 @@
+<?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.
+ -->
+
+<layer-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <item android:gravity="center"
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size">
+ <aapt:attr name="android:drawable">
+ <shape android:shape="oval">
+ <size
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"/>
+ <solid
+ android:color="#3C4043"/>
+ </shape>
+ </aapt:attr>
+ </item>
+ <item android:gravity="center"
+ android:width="48dp"
+ android:height="48dp">
+ <aapt:attr name="android:drawable">
+ <vector android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#8AB4F8"
+ android:pathData="M14,7l-5,5 5,5V7z"/>
+ </vector>
+ </aapt:attr>
+ </item>
+ <item>
+ <aapt:attr name="android:drawable">
+ <ripple android:color="?android:attr/colorControlHighlight"/>
+ </aapt:attr>
+ </item>
+</layer-list> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/hvac_increase_button.xml b/packages/CarSystemUI/res/drawable/hvac_increase_button.xml
new file mode 100644
index 000000000000..a3fca2233ddd
--- /dev/null
+++ b/packages/CarSystemUI/res/drawable/hvac_increase_button.xml
@@ -0,0 +1,53 @@
+<?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.
+ -->
+
+<layer-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <item android:gravity="center"
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size">
+ <aapt:attr name="android:drawable">
+ <shape android:shape="oval">
+ <size
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"/>
+ <solid
+ android:color="#3C4043"/>
+ </shape>
+ </aapt:attr>
+ </item>
+ <item android:gravity="center"
+ android:width="48dp"
+ android:height="48dp">
+ <aapt:attr name="android:drawable">
+ <vector android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#F28B82"
+ android:pathData="M10,17l5,-5 -5,-5v10z"/>
+ </vector>
+ </aapt:attr>
+ </item>
+ <item>
+ <aapt:attr name="android:drawable">
+ <ripple android:color="?android:attr/colorControlHighlight"/>
+ </aapt:attr>
+ </item>
+</layer-list> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/ic_mic_white.xml b/packages/CarSystemUI/res/drawable/ic_mic_white.xml
index 546b1a894e6a..71fcc5302d75 100644
--- a/packages/CarSystemUI/res/drawable/ic_mic_white.xml
+++ b/packages/CarSystemUI/res/drawable/ic_mic_white.xml
@@ -15,11 +15,11 @@
~ limitations under the License
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:viewportWidth="44"
- android:viewportHeight="44"
- android:width="44dp"
- android:height="44dp">
- <path
+ android:width="@dimen/system_bar_icon_drawing_size"
+ android:height="@dimen/system_bar_icon_drawing_size"
+ android:viewportWidth="44"
+ android:viewportHeight="44">
+<path
android:pathData="M22 25.6666667C25.0433333 25.6666667 27.4816667 23.21 27.4816667 20.1666667L27.5 9.16666667C27.5 6.12333333 25.0433333 3.66666667 22 3.66666667C18.9566667 3.66666667 16.5 6.12333333 16.5 9.16666667L16.5 20.1666667C16.5 23.21 18.9566667 25.6666667 22 25.6666667ZM31.7166667 20.1666667C31.7166667 25.6666667 27.06 29.5166667 22 29.5166667C16.94 29.5166667 12.2833333 25.6666667 12.2833333 20.1666667L9.16666667 20.1666667C9.16666667 26.4183333 14.1533333 31.5883333 20.1666667 32.4866667L20.1666667 38.5L23.8333333 38.5L23.8333333 32.4866667C29.8466667 31.6066667 34.8333333 26.4366667 34.8333333 20.1666667L31.7166667 20.1666667Z"
android:fillColor="@color/car_nav_icon_fill_color" />
</vector> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/layout/adjustable_temperature_view.xml b/packages/CarSystemUI/res/layout/adjustable_temperature_view.xml
new file mode 100644
index 000000000000..d19740932aa4
--- /dev/null
+++ b/packages/CarSystemUI/res/layout/adjustable_temperature_view.xml
@@ -0,0 +1,50 @@
+<?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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:paddingEnd="@dimen/hvac_container_padding"
+ android:paddingStart="@dimen/hvac_container_padding">
+
+ <ImageView
+ android:id="@+id/hvac_decrease_button"
+ android:layout_width="@dimen/hvac_temperature_button_size"
+ android:layout_height="@dimen/hvac_temperature_button_size"
+ android:scaleType="center"
+ android:src="@drawable/hvac_decrease_button"/>
+
+ <TextView
+ android:id="@+id/hvac_temperature_text"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:textSize="@dimen/hvac_temperature_text_size"
+ android:textColor="@color/system_bar_text_color"
+ android:paddingStart="@dimen/hvac_temperature_text_padding"
+ android:paddingEnd="@dimen/hvac_temperature_text_padding"
+ android:gravity="center"/>
+
+ <ImageView
+ android:id="@+id/hvac_increase_button"
+ android:layout_width="@dimen/hvac_temperature_button_size"
+ android:layout_height="@dimen/hvac_temperature_button_size"
+ android:scaleType="center"
+ android:src="@drawable/hvac_increase_button" />
+</LinearLayout> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/layout/car_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
index a49a6373a252..b07dde582e5f 100644
--- a/packages/CarSystemUI/res/layout/car_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2018 The Android Open Source Project
+ ~ 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.
@@ -12,7 +12,7 @@
~ 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
+ ~ limitations under the License.
-->
<com.android.systemui.car.navigationbar.CarNavigationBarView
@@ -21,115 +21,115 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/system_bar_background"
- android:orientation="vertical">
- <!--The 20dp padding is the difference between the background selected icon size and the ripple
- that was chosen, thus it's a hack to make it look pretty and not an official margin value-->
- <LinearLayout
+ android:gravity="center"
+ android:orientation="horizontal">
+
+ <RelativeLayout
android:id="@+id/nav_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1"
- android:gravity="center"
- android:layoutDirection="ltr"
- android:paddingEnd="20dp"
- android:paddingStart="20dp">
+ android:layoutDirection="ltr">
<com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/home"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
- systemui:icon="@drawable/car_ic_overview"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
- systemui:selectedIcon="@drawable/car_ic_overview_selected"
- systemui:highlightWhenSelected="true"
- />
-
- <Space
- android:layout_width="0dp"
+ android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_weight="1"/>
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/maps_nav"
- style="@style/NavigationBarButton"
- systemui:categories="android.intent.category.APP_MAPS"
- systemui:icon="@drawable/car_ic_navigation"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MAPS;launchFlags=0x14000000;end"
- systemui:selectedIcon="@drawable/car_ic_navigation_selected"
- systemui:highlightWhenSelected="true"
- />
-
- <Space
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"/>
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/music_nav"
- style="@style/NavigationBarButton"
- systemui:categories="android.intent.category.APP_MUSIC"
- systemui:icon="@drawable/car_ic_music"
- systemui:intent="intent:#Intent;action=android.car.intent.action.MEDIA_TEMPLATE;launchFlags=0x10000000;end"
- systemui:packages="com.android.car.media"
- systemui:selectedIcon="@drawable/car_ic_music_selected"
- systemui:highlightWhenSelected="true"
- />
-
- <Space
- android:layout_width="0dp"
+ android:layout_alignParentStart="true"
+ android:background="@null"
+ systemui:broadcast="true"
+ systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end">
+
+ <com.android.systemui.car.hvac.AdjustableTemperatureView
+ android:id="@+id/driver_hvac"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ systemui:hvacAreaId="49"
+ systemui:hvacTempFormat="%.0f\u00B0" />
+ </com.android.systemui.car.navigationbar.CarNavigationButton>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_weight="1"/>
+ android:layout_centerInParent="true"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:layoutDirection="ltr"
+ android:paddingEnd="@dimen/system_bar_button_group_padding"
+ android:paddingStart="@dimen/system_bar_button_group_padding">
+
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"/>
+
+ <com.android.systemui.car.navigationbar.CarNavigationButton
+ android:id="@+id/home"
+ style="@style/NavigationBarButton"
+ systemui:componentNames="com.android.car.carlauncher/.CarLauncher"
+ systemui:icon="@drawable/car_ic_home"
+ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"
+ systemui:selectedIcon="@drawable/car_ic_home_selected"/>
+
+ <com.android.systemui.car.navigationbar.CarNavigationButton
+ android:id="@+id/phone_nav"
+ style="@style/NavigationBarButton"
+ systemui:icon="@drawable/car_ic_phone"
+ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;package=com.android.car.dialer;launchFlags=0x10000000;end"
+ systemui:packages="com.android.car.dialer"
+ systemui:selectedIcon="@drawable/car_ic_phone_selected"/>
+
+ <com.android.systemui.car.navigationbar.CarNavigationButton
+ android:id="@+id/grid_nav"
+ style="@style/NavigationBarButton"
+ systemui:componentNames="com.android.car.carlauncher/.AppGridActivity"
+ systemui:icon="@drawable/car_ic_apps"
+ systemui:intent="intent:#Intent;component=com.android.car.carlauncher/.AppGridActivity;launchFlags=0x24000000;end"
+ systemui:selectedIcon="@drawable/car_ic_apps_selected"/>
+
+ <com.android.systemui.car.navigationbar.CarNavigationButton
+ android:id="@+id/hvac"
+ style="@style/NavigationBarButton"
+ systemui:icon="@drawable/car_ic_hvac"
+ systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
+ systemui:selectedIcon="@drawable/car_ic_hvac_selected"
+ systemui:broadcast="true"/>
+
+ <com.android.systemui.car.navigationbar.CarNavigationButton
+ android:id="@+id/notifications"
+ style="@style/NavigationBarButton"
+ systemui:icon="@drawable/car_ic_notification"
+ systemui:longIntent="intent:#Intent;component=com.android.car.bugreport/.BugReportActivity;end"/>
+
+ <com.android.systemui.car.navigationbar.AssitantButton
+ android:id="@+id/assist"
+ style="@style/NavigationBarButton"
+ systemui:icon="@drawable/ic_mic_white"
+ systemui:useDefaultAppIconForRole="true"/>
+
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"/>
+ </LinearLayout>
<com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/phone_nav"
- style="@style/NavigationBarButton"
- systemui:icon="@drawable/car_ic_phone"
- systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;package=com.android.car.dialer;launchFlags=0x10000000;end"
- systemui:packages="com.android.car.dialer"
- systemui:selectedIcon="@drawable/car_ic_phone_selected"
- systemui:highlightWhenSelected="true"
- />
-
- <Space
- android:layout_width="0dp"
+ android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_weight="1"/>
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/grid_nav"
- style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.carlauncher/.AppGridActivity"
- systemui:icon="@drawable/car_ic_apps"
- systemui:intent="intent:#Intent;component=com.android.car.carlauncher/.AppGridActivity;launchFlags=0x24000000;end"
- systemui:selectedIcon="@drawable/car_ic_apps_selected"
- systemui:highlightWhenSelected="true"
- />
-
- <Space
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"/>
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/notifications"
- style="@style/NavigationBarButton"
- systemui:icon="@drawable/car_ic_notification"
- systemui:longIntent="intent:#Intent;component=com.android.car.bugreport/.BugReportActivity;end"
- />
-
- <Space
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"/>
-
- <com.android.systemui.car.navigationbar.AssitantButton
- android:id="@+id/assist"
- style="@style/NavigationBarButton"
- systemui:icon="@drawable/ic_mic_white"
- systemui:useDefaultAppIconForRole="true"
- />
-
- </LinearLayout>
+ android:layout_alignParentEnd="true"
+ android:background="@null"
+ systemui:broadcast="true"
+ systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end">
+
+ <com.android.systemui.car.hvac.AdjustableTemperatureView
+ android:id="@+id/passenger_hvac"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentEnd="true"
+ android:gravity="center_vertical"
+ systemui:hvacAreaId="68"
+ systemui:hvacTempFormat="%.0f\u00B0" />
+ </com.android.systemui.car.navigationbar.CarNavigationButton>
+ </RelativeLayout>
<LinearLayout
android:id="@+id/lock_screen_nav_buttons"
@@ -142,5 +142,4 @@
android:paddingStart="@dimen/car_keyline_1"
android:visibility="gone"
/>
-
</com.android.systemui.car.navigationbar.CarNavigationBarView> \ 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 cdc29eec21cd..af8482a8c6a5 100644
--- a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
@@ -31,39 +31,44 @@
android:layoutDirection="ltr">
<FrameLayout
- android:id="@+id/left_hvac_container"
+ android:id="@+id/user_name_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
+ android:layout_toStartOf="@+id/clock_container"
>
<com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/hvacleft"
+ android:id="@+id/user_name"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@null"
- systemui:broadcast="true"
- systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
- />
-
- <com.android.systemui.car.hvac.AnimatedTemperatureView
- android:id="@+id/lefttext"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:paddingStart="@*android:dimen/car_padding_4"
- android:paddingEnd="16dp"
- android:gravity="center_vertical|start"
- android:minEms="4"
- android:textAppearance="@style/TextAppearance.CarStatus"
- systemui:hvacAreaId="49"
- systemui:hvacMaxText="@string/hvac_max_text"
- systemui:hvacMaxValue="@dimen/hvac_max_value"
- systemui:hvacMinText="@string/hvac_min_text"
- systemui:hvacMinValue="@dimen/hvac_min_value"
- systemui:hvacPivotOffset="60dp"
- systemui:hvacPropertyId="358614275"
- systemui:hvacTempFormat="%.0f\u00B0"
- />
+ systemui:icon="@null"
+ systemui:intent="intent:#Intent;component=com.android.car.settings/.users.UserSwitcherActivity;launchFlags=0x24000000;end"
+ >
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ >
+ <ImageView
+ android:id="@+id/user_avatar"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:src="@drawable/car_ic_user_icon"
+ android:paddingLeft="@dimen/system_bar_user_icon_padding"
+ android:paddingRight="@dimen/system_bar_user_icon_padding"
+ />
+ <TextView
+ android:id="@+id/user_name_text"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:textAppearance="@style/TextAppearance.SystemBar.Username"
+ android:maxLines="1"
+ />
+ </LinearLayout>
+ </com.android.systemui.car.navigationbar.CarNavigationButton>
</FrameLayout>
<FrameLayout
@@ -86,7 +91,8 @@
android:layout_gravity="center"
android:elevation="5dp"
android:singleLine="true"
- android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+ android:textAppearance="@style/TextAppearance.SystemBar.Clock"
+ systemui:amPmStyle="normal"
/>
</FrameLayout>
@@ -94,10 +100,9 @@
android:id="@+id/system_icon_area"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_centerHorizontal="true"
+ android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
- android:layout_toEndOf="@+id/clock_container"
- android:paddingStart="@*android:dimen/car_padding_1"
+ android:paddingEnd="@*android:dimen/car_padding_1"
android:gravity="center_vertical"
android:orientation="horizontal"
>
@@ -107,46 +112,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:paddingStart="4dp"
android:gravity="center_vertical"
/>
</LinearLayout>
-
- <FrameLayout
- android:id="@+id/right_hvac_container"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_alignParentEnd="true"
- >
-
- <com.android.systemui.car.navigationbar.CarNavigationButton
- android:id="@+id/hvacright"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@null"
- systemui:broadcast="true"
- systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
- />
-
- <com.android.systemui.car.hvac.AnimatedTemperatureView
- android:id="@+id/righttext"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:paddingStart="16dp"
- android:paddingEnd="@*android:dimen/car_padding_4"
- android:gravity="center_vertical|end"
- android:minEms="4"
- android:textAppearance="@style/TextAppearance.CarStatus"
- systemui:hvacAreaId="68"
- systemui:hvacMaxText="@string/hvac_max_text"
- systemui:hvacMaxValue="@dimen/hvac_max_value"
- systemui:hvacMinText="@string/hvac_min_text"
- systemui:hvacMinValue="@dimen/hvac_min_value"
- systemui:hvacPivotOffset="60dp"
- systemui:hvacPropertyId="358614275"
- systemui:hvacTempFormat="%.0f\u00B0"
- />
- </FrameLayout>
</RelativeLayout>
</com.android.systemui.car.navigationbar.CarNavigationBarView>
diff --git a/packages/CarSystemUI/res/layout/car_top_navigation_bar_unprovisioned.xml b/packages/CarSystemUI/res/layout/car_top_navigation_bar_unprovisioned.xml
index 9634950e4748..d9c149106451 100644
--- a/packages/CarSystemUI/res/layout/car_top_navigation_bar_unprovisioned.xml
+++ b/packages/CarSystemUI/res/layout/car_top_navigation_bar_unprovisioned.xml
@@ -55,10 +55,6 @@
android:minEms="4"
android:textAppearance="@style/TextAppearance.CarStatus"
systemui:hvacAreaId="49"
- systemui:hvacMaxText="@string/hvac_max_text"
- systemui:hvacMaxValue="@dimen/hvac_max_value"
- systemui:hvacMinText="@string/hvac_min_text"
- systemui:hvacMinValue="@dimen/hvac_min_value"
systemui:hvacPivotOffset="60dp"
systemui:hvacPropertyId="358614275"
systemui:hvacTempFormat="%.0f\u00B0"
@@ -133,10 +129,6 @@
android:minEms="4"
android:textAppearance="@style/TextAppearance.CarStatus"
systemui:hvacAreaId="68"
- systemui:hvacMaxText="@string/hvac_max_text"
- systemui:hvacMaxValue="@dimen/hvac_max_value"
- systemui:hvacMinText="@string/hvac_min_text"
- systemui:hvacMinValue="@dimen/hvac_min_value"
systemui:hvacPivotOffset="60dp"
systemui:hvacPropertyId="358614275"
systemui:hvacTempFormat="%.0f\u00B0"
diff --git a/packages/CarSystemUI/res/values/colors.xml b/packages/CarSystemUI/res/values/colors.xml
index ab9426593535..1e15affcbf48 100644
--- a/packages/CarSystemUI/res/values/colors.xml
+++ b/packages/CarSystemUI/res/values/colors.xml
@@ -31,6 +31,9 @@
<color name="docked_divider_background">@*android:color/car_grey_50</color>
<color name="system_bar_background_opaque">#ff172026</color>
+ <!-- colors for status bar -->
+ <color name="system_bar_user_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/config.xml b/packages/CarSystemUI/res/values/config.xml
index d3277ded6c5b..1fe2760e5b10 100644
--- a/packages/CarSystemUI/res/values/config.xml
+++ b/packages/CarSystemUI/res/values/config.xml
@@ -123,7 +123,6 @@
<item>com.android.systemui.volume.VolumeUI</item>
<item>com.android.systemui.statusbar.phone.StatusBar</item>
<item>com.android.systemui.keyboard.KeyboardUI</item>
- <item>com.android.systemui.pip.PipUI</item>
<item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
<item>com.android.systemui.LatencyTester</item>
<item>com.android.systemui.globalactions.GlobalActionsComponent</item>
diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml
index 8359dac6a30f..f02a8e7648c0 100644
--- a/packages/CarSystemUI/res/values/dimens.xml
+++ b/packages/CarSystemUI/res/values/dimens.xml
@@ -46,16 +46,23 @@
in frameworks/base/core package and thus will have no effect if
set here. See car_product overlay for car specific defaults-->
- <dimen name="status_bar_icon_drawing_size_dark">36dp</dimen>
- <dimen name="status_bar_icon_drawing_size">36dp</dimen>
+ <dimen name="system_bar_user_icon_padding">16dp</dimen>
+ <dimen name="system_bar_user_icon_drawing_size">36dp</dimen>
+ <dimen name="system_bar_button_group_padding">64dp</dimen>
+ <dimen name="system_bar_icon_drawing_size">44dp</dimen>
+
<!-- The amount by which to scale up the status bar icons. -->
<item name="status_bar_icon_scale_factor" format="float" type="dimen">1.75</item>
<dimen name="car_primary_icon_size">@*android:dimen/car_primary_icon_size</dimen>
+ <dimen name="hvac_container_padding">16dp</dimen>
+ <dimen name="hvac_temperature_text_size">56sp</dimen>
+ <dimen name="hvac_temperature_text_padding">8dp</dimen>
+ <dimen name="hvac_temperature_button_size">76dp</dimen>
<!--These values represent MIN and MAX for hvac-->
- <item name="hvac_min_value" format="float" type="dimen">0</item>
- <item name="hvac_max_value" format="float" type="dimen">126</item>
+ <item name="hvac_min_value_celsius" format="float" type="dimen">0</item>
+ <item name="hvac_max_value_celsius" format="float" type="dimen">126</item>
<!-- Largest size an avatar might need to be drawn in the user picker, status bar, or
quick settings header -->
diff --git a/packages/CarSystemUI/res/values/strings.xml b/packages/CarSystemUI/res/values/strings.xml
index 67fd5bb68521..fbdb5167fade 100644
--- a/packages/CarSystemUI/res/values/strings.xml
+++ b/packages/CarSystemUI/res/values/strings.xml
@@ -16,6 +16,8 @@
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Format for HVAC temperature (No decimal and the degree symbol) -->
+ <string name="hvac_temperature_format" translatable="false">%.0f\u00B0</string>
<!-- String to represent lowest setting of an HVAC system [CHAR LIMIT=10]-->
<string name="hvac_min_text">Min</string>
<!-- String to represent largest setting of an HVAC system [CHAR LIMIT=10]-->
diff --git a/packages/CarSystemUI/res/values/styles.xml b/packages/CarSystemUI/res/values/styles.xml
index e76373d4a4f7..0db17ac42a77 100644
--- a/packages/CarSystemUI/res/values/styles.xml
+++ b/packages/CarSystemUI/res/values/styles.xml
@@ -25,21 +25,29 @@
<item name="android:padding">22dp</item>
</style>
- <style name="TextAppearance.StatusBar.Clock"
- parent="@*android:style/TextAppearance.StatusBar.Icon">
- <item name="android:textSize">42sp</item>
- <item name="android:fontFamily">sans-serif-regular</item>
- <item name="android:textColor">@*android:color/car_grey_50</item>
+ <style name="TextAppearance.SystemBar.Clock"
+ parent="@*android:style/TextAppearance.StatusBar.Icon">
+ <item name="android:textSize">@dimen/car_body1_size</item>
+ <item name="android:textColor">@*android:color/car_headline3</item>
+ </style>
+
+ <style name="TextAppearance.SystemBar.Username"
+ parent="@android:style/TextAppearance.DeviceDefault">
+ <item name="android:textSize">@dimen/car_body3_size</item>
+ <item name="android:textColor">@color/system_bar_text_color</item>
</style>
<style name="TextAppearance.CarStatus" parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:textSize">@*android:dimen/car_body2_size</item>
- <item name="android:textColor">@*android:color/car_grey_50</item>
+ <item name="android:textColor">@color/system_bar_text_color</item>
</style>
<style name="NavigationBarButton">
- <item name="android:layout_height">96dp</item>
- <item name="android:layout_width">96dp</item>
+ <item name="android:layout_height">76dp</item>
+ <item name="android:layout_width">76dp</item>
+ <item name="android:layout_marginEnd">32dp</item>
+ <item name="android:padding">16dp</item>
+ <item name="android:gravity">center</item>
<item name="android:background">?android:attr/selectableItemBackground</item>
</style>
</resources> \ No newline at end of file
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
index 1a6fdfa9c996..51855dc648e9 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
@@ -20,7 +20,6 @@ import com.android.systemui.dagger.DependencyProvider;
import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.SystemUIModule;
-import com.android.systemui.pip.phone.dagger.PipModule;
import dagger.Subcomponent;
@@ -31,7 +30,6 @@ import dagger.Subcomponent;
@Subcomponent(modules = {
CarComponentBinder.class,
DependencyProvider.class,
- PipModule.class,
SystemUIModule.class,
CarSystemUIModule.class,
CarSystemUIBinder.class})
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
index 3971e18bb968..616e56288392 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
@@ -29,7 +29,6 @@ import com.android.systemui.globalactions.GlobalActionsComponent;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.dagger.KeyguardModule;
import com.android.systemui.onehanded.OneHandedUI;
-import com.android.systemui.pip.PipUI;
import com.android.systemui.power.PowerUI;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsModule;
@@ -101,12 +100,6 @@ public abstract class CarSystemUIBinder {
@ClassKey(OneHandedUI.class)
public abstract SystemUI bindOneHandedUI(OneHandedUI sysui);
- /** Inject into PipUI. */
- @Binds
- @IntoMap
- @ClassKey(PipUI.class)
- public abstract SystemUI bindPipUI(PipUI sysui);
-
/** Inject into PowerUI. */
@Binds
@IntoMap
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java
new file mode 100644
index 000000000000..4cac4456789d
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java
@@ -0,0 +1,108 @@
+/*
+ * 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.car.hvac;
+
+import static com.android.systemui.car.hvac.HvacController.convertToCelsius;
+import static com.android.systemui.car.hvac.HvacController.convertToFahrenheit;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+
+/**
+ * Displays temperature with a button to decrease and a button to increase on either side.
+ * Properties configured in the XML:
+ * hvacAreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
+ */
+public class AdjustableTemperatureView extends LinearLayout implements TemperatureView {
+
+ private HvacController mHvacController;
+ private float mCurrentTempC;
+ private TextView mTempTextView;
+ private boolean mDisplayInFahrenheit = false;
+
+ private final float mMinTempC;
+ private final float mMaxTempC;
+ private final int mAreaId;
+ private final String mTempFormat;
+
+ public AdjustableTemperatureView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TemperatureView);
+ mAreaId = typedArray.getInt(R.styleable.TemperatureView_hvacAreaId, -1);
+
+ LayoutInflater.from(context).inflate(R.layout.adjustable_temperature_view, /* root= */this);
+ mTempFormat = getResources().getString(R.string.hvac_temperature_format);
+ mMinTempC = getResources().getFloat(R.dimen.hvac_min_value_celsius);
+ mMaxTempC = getResources().getFloat(R.dimen.hvac_max_value_celsius);
+ initializeButtons();
+ }
+
+ @Override
+ public void setHvacController(HvacController controller) {
+ mHvacController = controller;
+ }
+
+ @Override
+ public void setTemperatureView(float tempC) {
+ if (tempC > mMaxTempC || tempC < mMinTempC) {
+ return;
+ }
+ if (mTempTextView == null) {
+ mTempTextView = findViewById(R.id.hvac_temperature_text);
+ }
+ mTempTextView.setText(String.format(mTempFormat,
+ mDisplayInFahrenheit ? convertToFahrenheit(tempC) : tempC));
+ mCurrentTempC = tempC;
+ }
+
+ @Override
+ public void setDisplayInFahrenheit(boolean displayFahrenheit) {
+ mDisplayInFahrenheit = displayFahrenheit;
+ setTemperatureView(mCurrentTempC);
+ }
+
+ @Override
+ public int getAreaId() {
+ return mAreaId;
+ }
+
+ private void initializeButtons() {
+ findViewById(R.id.hvac_decrease_button).setOnClickListener(v -> {
+ float newTemp = mDisplayInFahrenheit ? convertToCelsius(
+ convertToFahrenheit(mCurrentTempC) - 1) : (mCurrentTempC - 1);
+ setTemperature(newTemp, mAreaId);
+ });
+
+ findViewById(R.id.hvac_increase_button).setOnClickListener(v -> {
+ float newTemp = mDisplayInFahrenheit ? convertToCelsius(
+ convertToFahrenheit(mCurrentTempC) + 1) : (mCurrentTempC + 1);
+ setTemperature(newTemp, mAreaId);
+ });
+ }
+
+ private void setTemperature(float tempC, int zone) {
+ if (tempC < mMaxTempC && tempC > mMinTempC && mHvacController != null) {
+ mHvacController.setTemperature(tempC, zone);
+ }
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/AnimatedTemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/AnimatedTemperatureView.java
index a7294317f46c..567baa91cb59 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/AnimatedTemperatureView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/AnimatedTemperatureView.java
@@ -16,6 +16,8 @@
package com.android.systemui.car.hvac;
+import static com.android.systemui.car.hvac.HvacController.convertToFahrenheit;
+
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
@@ -40,9 +42,7 @@ import com.android.systemui.R;
* Simple text display of HVAC properties, It is designed to show mTemperature and is configured in
* the XML.
* XML properties:
- * hvacPropertyId - Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (16385)
- * hvacAreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
- * hvacTempFormat - Example: "%.1f\u00B0" (1 decimal and the degree symbol)
+ * hvacAreaId - Example: VehicleAreaSeat.SEAT_ROW_1_LEFT (1)
* hvacOrientaion = Example: left
*/
public class AnimatedTemperatureView extends FrameLayout implements TemperatureView {
@@ -84,7 +84,6 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
}
private final int mAreaId;
- private final int mPropertyId;
private final int mPivotOffset;
private final int mGravity;
private final int mTextAppearanceRes;
@@ -100,12 +99,13 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
private final TemperatureTextAnimator mTextAnimator;
boolean mDisplayInFahrenheit = false;
+ private HvacController mHvacController;
+
public AnimatedTemperatureView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs,
R.styleable.AnimatedTemperatureView);
mAreaId = typedArray.getInt(R.styleable.AnimatedTemperatureView_hvacAreaId, -1);
- mPropertyId = typedArray.getInt(R.styleable.AnimatedTemperatureView_hvacPropertyId, -1);
mPivotOffset =
typedArray.getDimensionPixelOffset(
R.styleable.AnimatedTemperatureView_hvacPivotOffset, 0);
@@ -115,11 +115,8 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
typedArray.getResourceId(R.styleable.AnimatedTemperatureView_android_textAppearance,
0);
mMinEms = typedArray.getInteger(R.styleable.AnimatedTemperatureView_android_minEms, 0);
- mMinValue = typedArray.getFloat(R.styleable.AnimatedTemperatureView_hvacMinValue,
- Float.NaN);
- mMaxValue = typedArray.getFloat(R.styleable.AnimatedTemperatureView_hvacMaxValue,
- Float.NaN);
-
+ mMinValue = getResources().getFloat(R.dimen.hvac_min_value_celsius);
+ mMaxValue = getResources().getFloat(R.dimen.hvac_max_value_celsius);
mPaddingRect =
new Rect(getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom());
@@ -138,15 +135,10 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
mBackgroundAnimator = new TemperatureBackgroundAnimator(this, background);
-
- String format = typedArray.getString(R.styleable.AnimatedTemperatureView_hvacTempFormat);
- format = (format == null) ? "%.1f\u00B0" : format;
- CharSequence minText = typedArray.getString(
- R.styleable.AnimatedTemperatureView_hvacMinText);
- CharSequence maxText = typedArray.getString(
- R.styleable.AnimatedTemperatureView_hvacMaxText);
- mTextAnimator = new TemperatureTextAnimator(this, textSwitcher, format, mPivotOffset,
- minText, maxText);
+ mTextAnimator = new TemperatureTextAnimator(this, textSwitcher,
+ getResources().getString(R.string.hvac_temperature_format), mPivotOffset,
+ getResources().getString(R.string.hvac_min_text),
+ getResources().getString(R.string.hvac_max_text));
addView(background, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
@@ -186,13 +178,18 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
return textView;
}
+ @Override
+ public void setHvacController(HvacController controller) {
+ mHvacController = controller;
+ }
+
/**
* Formats the float for display
*
* @param temp - The current temp or NaN
*/
@Override
- public void setTemp(float temp) {
+ public void setTemperatureView(float temp) {
if (mDisplayInFahrenheit) {
temp = convertToFahrenheit(temp);
}
@@ -252,15 +249,7 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
}
/**
- * @return propertiyId Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (358614275)
- */
- @Override
- public int getPropertyId() {
- return mPropertyId;
- }
-
- /**
- * @return hvac AreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
+ * @return hvac AreaId - Example: VehicleAreaSeat.SEAT_ROW_1_LEFT (1)
*/
@Override
public int getAreaId() {
@@ -272,6 +261,5 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV
super.onDetachedFromWindow();
mBackgroundAnimator.stopAnimations();
}
-
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java
index a4b6bfc58d3c..f7451dc6fdee 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java
@@ -18,12 +18,12 @@ package com.android.systemui.car.hvac;
import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
+import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
import android.car.Car;
import android.car.VehicleUnit;
import android.car.hardware.CarPropertyValue;
-import android.car.hardware.hvac.CarHvacManager;
-import android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback;
+import android.car.hardware.property.CarPropertyManager;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -34,10 +34,8 @@ import com.android.systemui.dagger.SysUISingleton;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
import javax.inject.Inject;
@@ -54,49 +52,64 @@ public class HvacController {
private final CarServiceProvider mCarServiceProvider;
private final Set<TemperatureView> mRegisteredViews = new HashSet<>();
- private CarHvacManager mHvacManager;
- private HashMap<HvacKey, List<TemperatureView>> mTempComponents = new HashMap<>();
-
- /**
- * Callback for getting changes from {@link CarHvacManager} and setting the UI elements to
- * match.
- */
- private final CarHvacEventCallback mHardwareCallback = new CarHvacEventCallback() {
- @Override
- public void onChangeEvent(final CarPropertyValue val) {
- try {
- int areaId = val.getAreaId();
- int propertyId = val.getPropertyId();
- List<TemperatureView> temperatureViews = mTempComponents.get(
- new HvacKey(propertyId, areaId));
- if (temperatureViews != null && !temperatureViews.isEmpty()) {
- float value = (float) val.getValue();
- if (DEBUG) {
- Log.d(TAG, "onChangeEvent: " + areaId + ":" + propertyId + ":" + value);
+ private CarPropertyManager mCarPropertyManager;
+ private HashMap<Integer, List<TemperatureView>> mTempComponents = new HashMap<>();
+
+ private final CarPropertyManager.CarPropertyEventCallback mHvacTemperatureSetCallback =
+ new CarPropertyManager.CarPropertyEventCallback() {
+ @Override
+ public void onChangeEvent(CarPropertyValue value) {
+ try {
+ int areaId = value.getAreaId();
+ List<TemperatureView> temperatureViews = mTempComponents.get(areaId);
+ if (temperatureViews != null && !temperatureViews.isEmpty()) {
+ float newTemp = (float) value.getValue();
+ if (DEBUG) {
+ Log.d(TAG, "onChangeEvent: " + areaId + ":" + value);
+ }
+ for (TemperatureView view : temperatureViews) {
+ view.setTemperatureView(newTemp);
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Failed handling hvac change event", e);
}
- for (TemperatureView tempView : temperatureViews) {
- tempView.setTemp(value);
+ }
+
+ @Override
+ public void onErrorEvent(int propId, int zone) {
+ Log.d(TAG, "HVAC error event, propertyId: " + propId + " zone: " + zone);
+ }
+ };
+
+ private final CarPropertyManager.CarPropertyEventCallback mTemperatureUnitChangeCallback =
+ new CarPropertyManager.CarPropertyEventCallback() {
+ @Override
+ public void onChangeEvent(CarPropertyValue value) {
+ if (!mRegisteredViews.isEmpty()) {
+ for (TemperatureView view : mRegisteredViews) {
+ view.setDisplayInFahrenheit(
+ value.getValue().equals(VehicleUnit.FAHRENHEIT));
+ }
}
- } // else the data is not of interest
- } catch (Exception e) {
- // catch all so we don't take down the sysui if a new data type is
- // introduced.
- Log.e(TAG, "Failed handling hvac change event", e);
- }
- }
+ }
- @Override
- public void onErrorEvent(final int propertyId, final int zone) {
- Log.d(TAG, "HVAC error event, propertyId: " + propertyId
- + " zone: " + zone);
- }
- };
+ @Override
+ public void onErrorEvent(int propId, int zone) {
+ Log.d(TAG, "HVAC error event, propertyId: " + propId + " zone: " + zone);
+ }
+ };
private final CarServiceProvider.CarServiceOnConnectedListener mCarServiceLifecycleListener =
car -> {
try {
- mHvacManager = (CarHvacManager) car.getCarManager(Car.HVAC_SERVICE);
- mHvacManager.registerCallback(mHardwareCallback);
+ mCarPropertyManager = (CarPropertyManager) car.getCarManager(
+ Car.PROPERTY_SERVICE);
+ mCarPropertyManager.registerCallback(mHvacTemperatureSetCallback,
+ HVAC_TEMPERATURE_SET, CarPropertyManager.SENSOR_RATE_ONCHANGE);
+ mCarPropertyManager.registerCallback(mTemperatureUnitChangeCallback,
+ HVAC_TEMPERATURE_DISPLAY_UNITS,
+ CarPropertyManager.SENSOR_RATE_ONCHANGE);
initComponents();
} catch (Exception e) {
Log.e(TAG, "Failed to correctly connect to HVAC", e);
@@ -109,8 +122,7 @@ public class HvacController {
}
/**
- * Create connection to the Car service. Note: call backs from the Car service
- * ({@link CarHvacManager}) will happen on the same thread this method was called from.
+ * Create connection to the Car service.
*/
public void connectToCarService() {
mCarServiceProvider.addListener(mCarServiceLifecycleListener);
@@ -124,21 +136,18 @@ public class HvacController {
return;
}
- HvacKey hvacKey = new HvacKey(temperatureView.getPropertyId(), temperatureView.getAreaId());
- if (!mTempComponents.containsKey(hvacKey)) {
- mTempComponents.put(hvacKey, new ArrayList<>());
+ int areaId = temperatureView.getAreaId();
+ if (!mTempComponents.containsKey(areaId)) {
+ mTempComponents.put(areaId, new ArrayList<>());
}
- mTempComponents.get(hvacKey).add(temperatureView);
+ mTempComponents.get(areaId).add(temperatureView);
initComponent(temperatureView);
mRegisteredViews.add(temperatureView);
}
private void initComponents() {
- Iterator<Map.Entry<HvacKey, List<TemperatureView>>> iterator =
- mTempComponents.entrySet().iterator();
- while (iterator.hasNext()) {
- Map.Entry<HvacKey, List<TemperatureView>> next = iterator.next();
+ for (Map.Entry<Integer, List<TemperatureView>> next : mTempComponents.entrySet()) {
List<TemperatureView> temperatureViews = next.getValue();
for (TemperatureView view : temperatureViews) {
initComponent(view);
@@ -147,29 +156,29 @@ public class HvacController {
}
private void initComponent(TemperatureView view) {
- int id = view.getPropertyId();
int zone = view.getAreaId();
if (DEBUG) {
- Log.d(TAG, "initComponent: " + zone + ":" + id);
+ Log.d(TAG, "initComponent: " + zone);
}
try {
- if (mHvacManager != null
- && mHvacManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
- VEHICLE_AREA_TYPE_GLOBAL)) {
- if (mHvacManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ if (mCarPropertyManager != null && mCarPropertyManager.isPropertyAvailable(
+ HVAC_TEMPERATURE_DISPLAY_UNITS, VEHICLE_AREA_TYPE_GLOBAL)) {
+ if (mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
VEHICLE_AREA_TYPE_GLOBAL) == VehicleUnit.FAHRENHEIT) {
view.setDisplayInFahrenheit(true);
}
-
}
- if (mHvacManager == null || !mHvacManager.isPropertyAvailable(id, zone)) {
- view.setTemp(Float.NaN);
+ if (mCarPropertyManager == null || !mCarPropertyManager.isPropertyAvailable(
+ HVAC_TEMPERATURE_SET, zone)) {
+ view.setTemperatureView(Float.NaN);
return;
}
- view.setTemp(mHvacManager.getFloatProperty(id, zone));
+ view.setTemperatureView(
+ mCarPropertyManager.getFloatProperty(HVAC_TEMPERATURE_SET, zone));
+ view.setHvacController(this);
} catch (Exception e) {
- view.setTemp(Float.NaN);
+ view.setTemperatureView(Float.NaN);
Log.e(TAG, "Failed to get value from hvac service", e);
}
}
@@ -199,30 +208,32 @@ public class HvacController {
}
/**
- * Key for storing {@link TemperatureView}s in a hash map
+ * Set the temperature in Celsius of the specified zone
*/
- private static class HvacKey {
-
- int mPropertyId;
- int mAreaId;
-
- private HvacKey(int propertyId, int areaId) {
- mPropertyId = propertyId;
- mAreaId = areaId;
+ public void setTemperature(float tempC, int zone) {
+ if (mCarPropertyManager != null) {
+ // Internally, all temperatures are represented in floating point Celsius
+ mCarPropertyManager.setFloatProperty(HVAC_TEMPERATURE_SET, zone, tempC);
}
+ }
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- HvacKey hvacKey = (HvacKey) o;
- return mPropertyId == hvacKey.mPropertyId
- && mAreaId == hvacKey.mAreaId;
- }
+ /**
+ * Convert the given temperature in Celsius into Fahrenheit
+ *
+ * @param tempC - The temperature in Celsius
+ * @return Temperature in Fahrenheit.
+ */
+ public static float convertToFahrenheit(float tempC) {
+ return (tempC * 9f / 5f) + 32;
+ }
- @Override
- public int hashCode() {
- return Objects.hash(mPropertyId, mAreaId);
- }
+ /**
+ * Convert the given temperature in Fahrenheit to Celsius
+ *
+ * @param tempF - The temperature in Fahrenheit.
+ * @return Temperature in Celsius.
+ */
+ public static float convertToCelsius(float tempF) {
+ return (float) ((tempF - 32) * 0.55555555556);
}
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextView.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextView.java
index 521a665da5f6..252f7830b72c 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextView.java
@@ -16,6 +16,8 @@
package com.android.systemui.car.hvac;
+import static com.android.systemui.car.hvac.HvacController.convertToFahrenheit;
+
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
@@ -27,24 +29,25 @@ import com.android.systemui.R;
* Simple text display of HVAC properties, It is designed to show temperature and is configured in
* the XML.
* XML properties:
- * hvacPropertyId - Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (16385)
- * hvacAreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
- * hvacTempFormat - Example: "%.1f\u00B0" (1 decimal and the degree symbol)
+ * hvacAreaId - Example: VehicleAreaSeat.SEAT_ROW_1_LEFT (1)
*/
public class TemperatureTextView extends TextView implements TemperatureView {
private final int mAreaId;
- private final int mPropertyId;
private final String mTempFormat;
+ private HvacController mHvacController;
private boolean mDisplayFahrenheit = false;
public TemperatureTextView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TemperatureView);
mAreaId = typedArray.getInt(R.styleable.TemperatureView_hvacAreaId, -1);
- mPropertyId = typedArray.getInt(R.styleable.TemperatureView_hvacPropertyId, -1);
- String format = typedArray.getString(R.styleable.TemperatureView_hvacTempFormat);
- mTempFormat = (format == null) ? "%.1f\u00B0" : format;
+ mTempFormat = getResources().getString(R.string.hvac_temperature_format);
+ }
+
+ @Override
+ public void setHvacController(HvacController controller) {
+ mHvacController = controller;
}
/**
@@ -53,7 +56,7 @@ public class TemperatureTextView extends TextView implements TemperatureView {
* @param temp - The current temp or NaN
*/
@Override
- public void setTemp(float temp) {
+ public void setTemperatureView(float temp) {
if (Float.isNaN(temp)) {
setText("--");
return;
@@ -70,15 +73,7 @@ public class TemperatureTextView extends TextView implements TemperatureView {
}
/**
- * @return propertiyId Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (16385)
- */
- @Override
- public int getPropertyId() {
- return mPropertyId;
- }
-
- /**
- * @return hvac AreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
+ * @return hvac AreaId - Example: VehicleAreaSeat.SEAT_ROW_1_LEFT (1)
*/
@Override
public int getAreaId() {
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureView.java
index 6b903fad505c..3c0e0acc446c 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureView.java
@@ -17,15 +17,23 @@
package com.android.systemui.car.hvac;
/**
- * Interface for Views that display temperature HVAC properties
+ * Interface for Views that display temperature HVAC properties.
*/
public interface TemperatureView {
+
+ /**
+ * Sets the {@link HvacController} to handle changes to HVAC properties. The View is only
+ * responsible for the UI to display temperature. It should not contain logic that makes direct
+ * changes to HVAC properties and instead use this {@link HvacController}.
+ */
+ void setHvacController(HvacController controller);
+
/**
* Formats the float for display
*
* @param temp - The current temp in Celsius or NaN
*/
- void setTemp(float temp);
+ void setTemperatureView(float temp);
/**
* Render the displayed temperature in Fahrenheit
@@ -35,22 +43,7 @@ public interface TemperatureView {
void setDisplayInFahrenheit(boolean displayFahrenheit);
/**
- * Convert the given temperature in Celsius into Fahrenheit
- *
- * @param realTemp - The temperature in Celsius
- * @return Temperature in Fahrenheit.
- */
- default float convertToFahrenheit(float realTemp) {
- return (realTemp * 9f / 5f) + 32;
- }
-
- /**
- * @return propertiyId Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (16385)
- */
- int getPropertyId();
-
- /**
- * @return hvac AreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
+ * @return hvac AreaId - Example: VehicleAreaSeat.SEAT_ROW_1_LEFT (1)
*/
int getAreaId();
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
index 51a883809aab..529083f4bab6 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
@@ -23,6 +23,7 @@ import android.view.ViewGroup;
import androidx.annotation.Nullable;
import com.android.systemui.car.hvac.HvacController;
+import com.android.systemui.car.statusbar.UserNameViewController;
import com.android.systemui.dagger.SysUISingleton;
import javax.inject.Inject;
@@ -38,6 +39,7 @@ public class CarNavigationBarController {
private final ButtonSelectionStateController mButtonSelectionStateController;
private final ButtonRoleHolderController mButtonRoleHolderController;
private final Lazy<HvacController> mHvacControllerLazy;
+ private final Lazy<UserNameViewController> mUserNameViewControllerLazy;
private boolean mShowTop;
private boolean mShowBottom;
@@ -60,12 +62,14 @@ public class CarNavigationBarController {
NavigationBarViewFactory navigationBarViewFactory,
ButtonSelectionStateController buttonSelectionStateController,
Lazy<HvacController> hvacControllerLazy,
+ Lazy<UserNameViewController> userNameViewControllerLazy,
ButtonRoleHolderController buttonRoleHolderController,
SystemBarConfigs systemBarConfigs) {
mContext = context;
mNavigationBarViewFactory = navigationBarViewFactory;
mButtonSelectionStateController = buttonSelectionStateController;
mHvacControllerLazy = hvacControllerLazy;
+ mUserNameViewControllerLazy = userNameViewControllerLazy;
mButtonRoleHolderController = buttonRoleHolderController;
// Read configuration.
@@ -109,6 +113,7 @@ public class CarNavigationBarController {
mHvacControllerLazy.get().removeAllComponents();
mButtonSelectionStateController.removeAll();
mButtonRoleHolderController.removeAll();
+ mUserNameViewControllerLazy.get().removeAll();
}
/** Gets the top window if configured to do so. */
@@ -218,6 +223,7 @@ public class CarNavigationBarController {
mButtonSelectionStateController.addAllButtonsWithSelectionState(view);
mButtonRoleHolderController.addAllButtonsWithRoleName(view);
mHvacControllerLazy.get().addTemperatureViewToController(view);
+ mUserNameViewControllerLazy.get().addUserNameView(view);
}
/** Sets a touch listener for the top navigation bar. */
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
index fe4cba8e73cd..8d91e7eae91a 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
@@ -54,8 +54,8 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.wm.shell.animation.FlingAnimationUtils;
import java.util.concurrent.Executor;
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/UserNameViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/UserNameViewController.java
new file mode 100644
index 000000000000..5ef8aa19b182
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/UserNameViewController.java
@@ -0,0 +1,132 @@
+/*
+ * 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.car.statusbar;
+
+import android.car.Car;
+import android.car.user.CarUserManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.dagger.SysUISingleton;
+
+import javax.inject.Inject;
+
+/**
+ * Controls a TextView with the current driver's username
+ */
+@SysUISingleton
+public class UserNameViewController {
+ private static final String TAG = "UserNameViewController";
+
+ private Context mContext;
+ private UserManager mUserManager;
+ private CarUserManager mCarUserManager;
+ private CarServiceProvider mCarServiceProvider;
+ private CarDeviceProvisionedController mCarDeviceProvisionedController;
+ private BroadcastDispatcher mBroadcastDispatcher;
+ private TextView mUserNameView;
+
+ private final BroadcastReceiver mUserUpdateReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ updateUser(mCarDeviceProvisionedController.getCurrentUser());
+ }
+ };
+
+ private final CarUserManager.UserLifecycleListener mUserLifecycleListener =
+ new CarUserManager.UserLifecycleListener() {
+ @Override
+ public void onEvent(CarUserManager.UserLifecycleEvent event) {
+ if (event.getEventType()
+ == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
+ updateUser(event.getUserId());
+ }
+ }
+ };
+
+ @Inject
+ public UserNameViewController(Context context, CarServiceProvider carServiceProvider,
+ UserManager userManager, BroadcastDispatcher broadcastDispatcher,
+ CarDeviceProvisionedController carDeviceProvisionedController) {
+ mContext = context;
+ mCarServiceProvider = carServiceProvider;
+ mUserManager = userManager;
+ mBroadcastDispatcher = broadcastDispatcher;
+ mCarDeviceProvisionedController = carDeviceProvisionedController;
+ }
+
+ /**
+ * Find the {@link TextView} for the driver's user name from a view and if found set it with the
+ * current driver's user name.
+ */
+ public void addUserNameView(View v) {
+ TextView userNameView = v.findViewById(R.id.user_name_text);
+ if (userNameView != null) {
+ if (mUserNameView == null) {
+ registerForUserChangeEvents();
+ }
+ mUserNameView = userNameView;
+ updateUser(mCarDeviceProvisionedController.getCurrentUser());
+ }
+ }
+
+ /**
+ * Clean up the controller and unregister receiver.
+ */
+ public void removeAll() {
+ mBroadcastDispatcher.unregisterReceiver(mUserUpdateReceiver);
+ if (mCarUserManager != null) {
+ mCarUserManager.removeListener(mUserLifecycleListener);
+ }
+ }
+
+ private void registerForUserChangeEvents() {
+ // Register for user switching
+ mCarServiceProvider.addListener(car -> {
+ mCarUserManager = (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE);
+ if (mCarUserManager != null) {
+ mCarUserManager.addListener(Runnable::run, mUserLifecycleListener);
+ } else {
+ Log.e(TAG, "CarUserManager could not be obtained.");
+ }
+ });
+ // Also register for user info changing
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
+ mBroadcastDispatcher.registerReceiver(mUserUpdateReceiver, filter, /* executor= */ null,
+ UserHandle.ALL);
+ }
+
+ private void updateUser(int userId) {
+ if (mUserNameView != null) {
+ UserInfo currentUserInfo = mUserManager.getUserInfo(userId);
+ mUserNameView.setText(currentUserInfo.name);
+ }
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
index 1b00c6301011..d928ad0f42c9 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java
@@ -34,7 +34,7 @@ import androidx.annotation.CallSuper;
import com.android.systemui.R;
import com.android.systemui.car.CarDeviceProvisionedController;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.statusbar.FlingAnimationUtils;
+import com.android.wm.shell.animation.FlingAnimationUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java
new file mode 100644
index 000000000000..e8850def6bcd
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java
@@ -0,0 +1,174 @@
+/*
+ * 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.car.hvac;
+
+import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
+import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
+import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
+
+import static com.android.systemui.car.hvac.HvacController.convertToCelsius;
+import static com.android.systemui.car.hvac.HvacController.convertToFahrenheit;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.car.Car;
+import android.car.VehicleUnit;
+import android.car.hardware.property.CarPropertyManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.widget.TextView;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.car.CarSystemUiTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@CarSystemUiTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class AdjustableTemperatureViewTest extends SysuiTestCase {
+
+ private static final float TEMP_CELSIUS = 22.0f;
+ private final String mFormat = getContext().getString(R.string.hvac_temperature_format);
+ private AdjustableTemperatureView mAdjustableTemperatureView;
+ private HvacController mHvacController;
+
+ @Mock
+ private Car mCar;
+ @Mock
+ private CarPropertyManager mCarPropertyManager;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mCar.isConnected()).thenReturn(true);
+ when(mCar.getCarManager(Car.PROPERTY_SERVICE)).thenReturn(mCarPropertyManager);
+
+ CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar);
+ mHvacController = new HvacController(carServiceProvider);
+ mHvacController.connectToCarService();
+ mAdjustableTemperatureView = new AdjustableTemperatureView(getContext(), /* attrs= */ null);
+ mAdjustableTemperatureView.setHvacController(mHvacController);
+ }
+
+ @Test
+ public void addTemperatureViewToController_setsTemperatureView() {
+ when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
+ anyInt())).thenReturn(true);
+ when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
+ TEMP_CELSIUS);
+
+ mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
+
+ TextView tempText = mAdjustableTemperatureView.findViewById(R.id.hvac_temperature_text);
+ assertEquals(tempText.getText(), String.format(mFormat, TEMP_CELSIUS));
+ }
+
+ @Test
+ public void setTemperatureToFahrenheit_callsViewSetDisplayInFahrenheit() {
+ when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
+ anyInt())).thenReturn(true);
+ when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
+ TEMP_CELSIUS);
+ when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(true);
+ when(mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(VehicleUnit.FAHRENHEIT);
+
+ mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
+
+ TextView tempText = mAdjustableTemperatureView.findViewById(R.id.hvac_temperature_text);
+ assertEquals(tempText.getText(), String.format(mFormat, convertToFahrenheit(TEMP_CELSIUS)));
+ }
+
+ @Test
+ public void adjustableViewIncreaseButton_setsTempWithCarPropertyManager() {
+ when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
+ anyInt())).thenReturn(true);
+ when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
+ TEMP_CELSIUS);
+ mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
+
+ mAdjustableTemperatureView.findViewById(R.id.hvac_increase_button).callOnClick();
+
+ verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(),
+ eq(TEMP_CELSIUS + 1));
+ }
+
+ @Test
+ public void adjustableViewDecreaseButton_setsTempWithCarPropertyManager() {
+ when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
+ anyInt())).thenReturn(true);
+ when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
+ TEMP_CELSIUS);
+ mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
+
+ mAdjustableTemperatureView.findViewById(R.id.hvac_decrease_button).callOnClick();
+
+ verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(),
+ eq(TEMP_CELSIUS - 1));
+ }
+
+ @Test
+ public void adjustableViewIncreaseButton_inFahrenheit_setsTempWithCarPropertyManager() {
+ when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
+ anyInt())).thenReturn(true);
+ when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
+ TEMP_CELSIUS);
+ when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(true);
+ when(mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(VehicleUnit.FAHRENHEIT);
+ mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
+
+ mAdjustableTemperatureView.findViewById(R.id.hvac_increase_button).callOnClick();
+
+ verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(),
+ eq(convertToCelsius(convertToFahrenheit(TEMP_CELSIUS) + 1)));
+ }
+
+ @Test
+ public void adjustableViewDecreaseButton_inFahrenheit_setsTempWithCarPropertyManager() {
+ when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
+ anyInt())).thenReturn(true);
+ when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
+ TEMP_CELSIUS);
+ when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(true);
+ when(mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(VehicleUnit.FAHRENHEIT);
+ mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
+
+ mAdjustableTemperatureView.findViewById(R.id.hvac_decrease_button).callOnClick();
+
+ verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(),
+ eq(convertToCelsius(convertToFahrenheit(TEMP_CELSIUS) - 1)));
+ }
+}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java
index e179ef1ce2a4..9912657d78e1 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java
@@ -16,7 +16,13 @@
package com.android.systemui.car.hvac;
+import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
+import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
+import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
+
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -24,7 +30,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.car.Car;
-import android.car.hardware.hvac.CarHvacManager;
+import android.car.VehicleUnit;
+import android.car.hardware.property.CarPropertyManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -46,92 +53,91 @@ import org.mockito.MockitoAnnotations;
@SmallTest
public class HvacControllerTest extends SysuiTestCase {
- private static final int PROPERTY_ID = 1;
private static final int AREA_ID = 1;
- private static final float VALUE = 72.0f;
+ private static final float TEMP = 72.0f;
private HvacController mHvacController;
- private CarServiceProvider mCarServiceProvider;
@Mock
private Car mCar;
@Mock
- private CarHvacManager mCarHvacManager;
+ private CarPropertyManager mCarPropertyManager;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mCar.isConnected()).thenReturn(true);
- when(mCar.getCarManager(Car.HVAC_SERVICE)).thenReturn(mCarHvacManager);
+ when(mCar.getCarManager(Car.PROPERTY_SERVICE)).thenReturn(mCarPropertyManager);
- mCarServiceProvider = new CarServiceProvider(mContext, mCar);
- mHvacController = new HvacController(mCarServiceProvider);
+ CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar);
+ mHvacController = new HvacController(carServiceProvider);
mHvacController.connectToCarService();
}
@Test
public void connectToCarService_registersCallback() {
- verify(mCarHvacManager).registerCallback(any());
+ verify(mCarPropertyManager).registerCallback(any(), eq(HVAC_TEMPERATURE_SET), anyFloat());
+ verify(mCarPropertyManager).registerCallback(any(), eq(HVAC_TEMPERATURE_DISPLAY_UNITS),
+ anyFloat());
}
@Test
public void addTemperatureViewToController_usingTemperatureView_registersView() {
- TemperatureTextView v = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE);
+ TemperatureTextView v = setupMockTemperatureTextView(AREA_ID, TEMP);
mHvacController.addTemperatureViewToController(v);
- verify(v).setTemp(VALUE);
+ verify(v).setTemperatureView(TEMP);
}
@Test
public void addTemperatureViewToController_usingSameTemperatureView_registersFirstView() {
- TemperatureTextView v = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE);
+ TemperatureTextView v = setupMockTemperatureTextView(AREA_ID, TEMP);
mHvacController.addTemperatureViewToController(v);
- verify(v).setTemp(VALUE);
- resetTemperatureView(v, PROPERTY_ID, AREA_ID);
+ verify(v).setTemperatureView(TEMP);
+ resetTemperatureView(v, AREA_ID);
mHvacController.addTemperatureViewToController(v);
- verify(v, never()).setTemp(VALUE);
+ verify(v, never()).setTemperatureView(TEMP);
}
@Test
public void addTemperatureViewToController_usingDifferentTemperatureView_registersBothViews() {
- TemperatureTextView v1 = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE);
+ TemperatureTextView v1 = setupMockTemperatureTextView(AREA_ID, TEMP);
mHvacController.addTemperatureViewToController(v1);
- verify(v1).setTemp(VALUE);
+ verify(v1).setTemperatureView(TEMP);
TemperatureTextView v2 = setupMockTemperatureTextView(
- PROPERTY_ID + 1,
AREA_ID + 1,
- VALUE + 1);
+ TEMP + 1);
mHvacController.addTemperatureViewToController(v2);
- verify(v2).setTemp(VALUE + 1);
+ verify(v2).setTemperatureView(TEMP + 1);
}
@Test
- public void removeAllComponents_ableToRegisterSameView() {
- TemperatureTextView v = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE);
- mHvacController.addTemperatureViewToController(v);
- verify(v).setTemp(VALUE);
-
- mHvacController.removeAllComponents();
- resetTemperatureView(v, PROPERTY_ID, AREA_ID);
+ public void setTemperatureToFahrenheit_callsViewSetDisplayInFahrenheit() {
+ when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(true);
+ when(mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(VehicleUnit.FAHRENHEIT);
+ TemperatureTextView v = setupMockTemperatureTextView(AREA_ID, TEMP);
mHvacController.addTemperatureViewToController(v);
- verify(v).setTemp(VALUE);
+
+ verify(v).setDisplayInFahrenheit(true);
+ verify(v).setTemperatureView(TEMP);
}
- private TemperatureTextView setupMockTemperatureTextView(int propertyId, int areaId,
- float value) {
+ private TemperatureTextView setupMockTemperatureTextView(int areaId, float value) {
TemperatureTextView v = mock(TemperatureTextView.class);
- resetTemperatureView(v, propertyId, areaId);
- when(mCarHvacManager.isPropertyAvailable(propertyId, areaId)).thenReturn(true);
- when(mCarHvacManager.getFloatProperty(propertyId, areaId)).thenReturn(value);
+ resetTemperatureView(v, areaId);
+ when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_SET, areaId)).thenReturn(
+ true);
+ when(mCarPropertyManager.getFloatProperty(HVAC_TEMPERATURE_SET, areaId)).thenReturn(value);
return v;
}
- private void resetTemperatureView(TemperatureTextView view, int propertyId, int areaId) {
+ private void resetTemperatureView(TemperatureTextView view, int areaId) {
reset(view);
- when(view.getPropertyId()).thenReturn(propertyId);
when(view.getAreaId()).thenReturn(areaId);
}
}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/TemperatureTextViewTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/TemperatureTextViewTest.java
new file mode 100644
index 000000000000..e97d9d9b3f6a
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/TemperatureTextViewTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.car.hvac;
+
+import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
+import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
+import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_SET;
+
+import static com.android.systemui.car.hvac.HvacController.convertToFahrenheit;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.car.Car;
+import android.car.VehicleUnit;
+import android.car.hardware.property.CarPropertyManager;
+import android.content.Context;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.car.CarSystemUiTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@CarSystemUiTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class TemperatureTextViewTest extends SysuiTestCase {
+ private static final float TEMP = 72.0f;
+ private final String mFormat = getContext().getString(R.string.hvac_temperature_format);
+ private HvacController mHvacController;
+ private TemperatureTextView mTextView;
+
+ @Mock
+ private Context mContext;
+
+ @Mock
+ private Car mCar;
+ @Mock
+ private CarPropertyManager mCarPropertyManager;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mCar.isConnected()).thenReturn(true);
+ when(mCar.getCarManager(Car.PROPERTY_SERVICE)).thenReturn(mCarPropertyManager);
+
+ CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar);
+ mHvacController = new HvacController(carServiceProvider);
+ mHvacController.connectToCarService();
+ mTextView = new TemperatureTextView(getContext(), /* attrs= */ null);
+ }
+
+ @Test
+ public void addTemperatureViewToController_usingTemperatureView_registersView() {
+ when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
+ anyInt())).thenReturn(true);
+ when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
+ TEMP);
+
+ mHvacController.addTemperatureViewToController(mTextView);
+
+ assertEquals(mTextView.getText(), String.format(mFormat, TEMP));
+ }
+
+ @Test
+ public void setTemperatureToFahrenheit_callsViewSetDisplayInFahrenheit() {
+ when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
+ anyInt())).thenReturn(true);
+ when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
+ TEMP);
+ when(mCarPropertyManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(true);
+ when(mCarPropertyManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
+ VEHICLE_AREA_TYPE_GLOBAL)).thenReturn(VehicleUnit.FAHRENHEIT);
+
+ mHvacController.addTemperatureViewToController(mTextView);
+
+ assertEquals(mTextView.getText(), String.format(mFormat, convertToFahrenheit(TEMP)));
+ }
+}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
index 84c840477302..0b3ac2a98e3a 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
@@ -33,6 +33,7 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.car.hvac.HvacController;
+import com.android.systemui.car.statusbar.UserNameViewController;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -62,6 +63,8 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
private ButtonRoleHolderController mButtonRoleHolderController;
@Mock
private HvacController mHvacController;
+ @Mock
+ private UserNameViewController mUserNameViewController;
@Before
public void setUp() throws Exception {
@@ -77,7 +80,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
private CarNavigationBarController createNavigationBarController() {
return new CarNavigationBarController(mContext, mNavigationBarViewFactory,
mButtonSelectionStateController, () -> mHvacController,
- mButtonRoleHolderController,
+ () -> mUserNameViewController, mButtonRoleHolderController,
new SystemBarConfigs(mTestableResources.getResources()));
}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/statusbar/UserNameViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/statusbar/UserNameViewControllerTest.java
new file mode 100644
index 000000000000..8f9e56edf419
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/statusbar/UserNameViewControllerTest.java
@@ -0,0 +1,155 @@
+/*
+ * 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.car.statusbar;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import android.car.Car;
+import android.car.user.CarUserManager;
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.content.pm.UserInfo;
+import android.os.UserManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.car.CarSystemUiTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@CarSystemUiTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class UserNameViewControllerTest extends SysuiTestCase {
+
+ private final UserInfo mUserInfo1 = new UserInfo(/* id= */ 0, "Test User Name", /* flags= */ 0);
+ private final UserInfo mUserInfo2 = new UserInfo(/* id= */ 1, "Another User", /* flags= */ 0);
+ private TextView mTextView;
+ private UserNameViewController mUserNameViewController;
+
+ @Mock
+ private Car mCar;
+ @Mock
+ private CarUserManager mCarUserManager;
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private CarDeviceProvisionedController mCarDeviceProvisionedController;
+ @Mock
+ private BroadcastDispatcher mBroadcastDispatcher;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ when(mUserManager.getUserInfo(mUserInfo1.id)).thenReturn(mUserInfo1);
+ when(mUserManager.getUserInfo(mUserInfo2.id)).thenReturn(mUserInfo2);
+ when(mCar.isConnected()).thenReturn(true);
+ when(mCar.getCarManager(Car.CAR_USER_SERVICE)).thenReturn(mCarUserManager);
+
+ CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar);
+ mUserNameViewController = new UserNameViewController(getContext(), carServiceProvider,
+ mUserManager, mBroadcastDispatcher, mCarDeviceProvisionedController);
+
+ mTextView = new TextView(getContext());
+ mTextView.setId(R.id.user_name_text);
+ }
+
+ @Test
+ public void addUserNameViewToController_updatesUserNameView() {
+ when(mCarDeviceProvisionedController.getCurrentUser()).thenReturn(mUserInfo1.id);
+
+ mUserNameViewController.addUserNameView(mTextView);
+
+ assertEquals(mTextView.getText(), mUserInfo1.name);
+ }
+
+ @Test
+ public void addUserNameViewToController_withNoTextView_doesNotUpdate() {
+ View nullView = new View(getContext());
+ mUserNameViewController.addUserNameView(nullView);
+
+ assertEquals(mTextView.getText(), "");
+ verifyZeroInteractions(mCarDeviceProvisionedController);
+ verifyZeroInteractions(mCarUserManager);
+ verifyZeroInteractions(mUserManager);
+ }
+
+ @Test
+ public void userLifecycleListener_onUserSwitchLifecycleEvent_updatesUserNameView() {
+ ArgumentCaptor<CarUserManager.UserLifecycleListener> userLifecycleListenerArgumentCaptor =
+ ArgumentCaptor.forClass(CarUserManager.UserLifecycleListener.class);
+ when(mCarDeviceProvisionedController.getCurrentUser()).thenReturn(mUserInfo1.id);
+ // Add the initial TextView, which registers the UserLifecycleListener
+ mUserNameViewController.addUserNameView(mTextView);
+ assertEquals(mTextView.getText(), mUserInfo1.name);
+ verify(mCarUserManager).addListener(any(), userLifecycleListenerArgumentCaptor.capture());
+
+ CarUserManager.UserLifecycleEvent event = new CarUserManager.UserLifecycleEvent(
+ CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING, /* from= */ mUserInfo1.id,
+ /* to= */ mUserInfo2.id);
+ userLifecycleListenerArgumentCaptor.getValue().onEvent(event);
+
+ assertEquals(mTextView.getText(), mUserInfo2.name);
+ }
+
+ @Test
+ public void userInfoChangedBroadcast_withoutInitializingUserNameView_doesNothing() {
+ getContext().sendBroadcast(new Intent(Intent.ACTION_USER_INFO_CHANGED));
+
+ assertEquals(mTextView.getText(), "");
+ verifyZeroInteractions(mCarDeviceProvisionedController);
+ }
+
+ @Test
+ public void userInfoChangedBroadcast_withUserNameViewInitialized_updatesUserNameView() {
+ ArgumentCaptor<BroadcastReceiver> broadcastReceiverArgumentCaptor = ArgumentCaptor.forClass(
+ BroadcastReceiver.class);
+ when(mCarDeviceProvisionedController.getCurrentUser()).thenReturn(mUserInfo1.id);
+ mUserNameViewController.addUserNameView(mTextView);
+ assertEquals(mTextView.getText(), mUserInfo1.name);
+ verify(mBroadcastDispatcher).registerReceiver(broadcastReceiverArgumentCaptor.capture(),
+ any(), any(), any());
+
+ reset(mCarDeviceProvisionedController);
+ when(mCarDeviceProvisionedController.getCurrentUser()).thenReturn(mUserInfo2.id);
+ broadcastReceiverArgumentCaptor.getValue().onReceive(getContext(),
+ new Intent(Intent.ACTION_USER_INFO_CHANGED));
+
+ assertEquals(mTextView.getText(), mUserInfo2.name);
+ verify(mCarDeviceProvisionedController).getCurrentUser();
+ }
+}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java
index 7311cdb68a3c..bed803eedc22 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java
@@ -40,8 +40,8 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarDeviceProvisionedController;
import com.android.systemui.car.CarSystemUiTest;
-import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.tests.R;
+import com.android.wm.shell.animation.FlingAnimationUtils;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 7f4f580abf94..6db3d0b8dff2 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -516,7 +516,7 @@
android:excludeFromRecents="true"
android:visibleToInstantApps="true"/>
- <!-- started from PipUI -->
+ <!-- started from PipController -->
<activity
android:name=".pip.tv.PipMenuActivity"
android:permission="com.android.systemui.permission.SELF"
diff --git a/packages/SystemUI/README.md b/packages/SystemUI/README.md
index 148fabbbaf2c..bd93c396aa16 100644
--- a/packages/SystemUI/README.md
+++ b/packages/SystemUI/README.md
@@ -115,10 +115,6 @@ Shows UI for keyboard shortcuts (triggered by keyboard shortcut).
Shows the overlay controls when One handed is triggered.
-### [com.android.systemui.pip.PipUI](/packages/SystemUI/src/com/android/systemui/pip/PipUI.java)
-
-Shows the overlay controls when Pip is showing.
-
### [com.android.systemui.shortcut.ShortcutKeyDispatcher](/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java)
Dispatches shortcut to System UI components.
diff --git a/packages/SystemUI/res/layout-land-television/volume_dialog.xml b/packages/SystemUI/res/layout-land-television/volume_dialog.xml
index 56d847c6aa2e..8179bf48e7ab 100644
--- a/packages/SystemUI/res/layout-land-television/volume_dialog.xml
+++ b/packages/SystemUI/res/layout-land-television/volume_dialog.xml
@@ -24,23 +24,17 @@
<FrameLayout
android:id="@+id/volume_dialog"
- android:minWidth="@dimen/volume_dialog_panel_width"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:background="@android:color/transparent"
- android:paddingRight="@dimen/volume_dialog_panel_transparent_padding_right"
- android:paddingTop="@dimen/volume_dialog_panel_transparent_padding"
- android:paddingBottom="@dimen/volume_dialog_panel_transparent_padding"
- android:paddingLeft="@dimen/volume_dialog_panel_transparent_padding"
+ android:padding="@dimen/volume_dialog_panel_transparent_padding"
android:clipToPadding="false">
<LinearLayout
android:id="@+id/main"
android:layout_width="wrap_content"
- android:minWidth="@dimen/volume_dialog_panel_width"
android:layout_height="wrap_content"
- android:layout_marginTop="68dp"
android:layout_gravity="right"
android:orientation="vertical"
android:translationZ="@dimen/volume_dialog_elevation"
@@ -52,7 +46,6 @@
android:id="@+id/volume_dialog_rows"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:minWidth="@dimen/volume_dialog_panel_width"
android:gravity="center"
android:orientation="horizontal">
<!-- volume rows added and removed here! :-) -->
diff --git a/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml b/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
index e9641936f357..d28d5664d725 100644
--- a/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml
@@ -16,8 +16,8 @@
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:tag="row"
- android:layout_width="@dimen/volume_dialog_row_width"
- android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/volume_dialog_row_height"
android:background="@android:color/transparent"
android:clipChildren="false"
android:clipToPadding="false"
@@ -30,15 +30,17 @@
android:background="@android:color/transparent"
android:gravity="center"
android:layout_gravity="center"
- android:orientation="horizontal" >
- <com.android.keyguard.AlphaOptimizedImageButton
- android:id="@+id/volume_row_icon"
- style="@style/VolumeButtons"
+ android:orientation="vertical" >
+ <TextView
+ android:id="@+id/volume_number"
android:layout_width="@dimen/tv_volume_dialog_bubble_size"
android:layout_height="@dimen/tv_volume_dialog_bubble_size"
+ android:maxLength="2"
+ android:gravity="center"
+ android:fontFeatureSettings="tnum"
android:background="@drawable/tv_volume_dialog_circle"
- android:tint="@color/accent_tint_color_selector"
- android:soundEffectsEnabled="false" />
+ android:textSize="@dimen/tv_volume_number_text_size"
+ android:textColor="@color/accent_tint_color_selector"/>
<TextView
android:id="@+id/volume_row_header"
android:layout_width="wrap_content"
@@ -51,28 +53,24 @@
android:textAppearance="@style/TextAppearance.Volume.Header" />
<FrameLayout
android:id="@+id/volume_row_slider_frame"
- android:layout_height="match_parent"
- android:layoutDirection="ltr"
- android:layout_width="@dimen/volume_dialog_row_width">
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/volume_dialog_row_height">
<SeekBar
android:id="@+id/volume_row_slider"
android:clickable="false"
- android:layout_width="@dimen/volume_dialog_row_width"
+ android:layout_width="@dimen/volume_dialog_row_height"
android:layout_height="match_parent"
- android:layoutDirection="ltr"
android:layout_gravity="center"
- android:rotation="0" />
+ android:rotation="270" />
</FrameLayout>
- <TextView
- android:id="@+id/volume_number"
+ <com.android.keyguard.AlphaOptimizedImageButton
+ android:id="@+id/volume_row_icon"
+ style="@style/VolumeButtons"
android:layout_width="@dimen/tv_volume_dialog_bubble_size"
android:layout_height="@dimen/tv_volume_dialog_bubble_size"
- android:maxLength="2"
- android:gravity="center"
android:background="@drawable/tv_volume_dialog_circle"
- android:fontFeatureSettings="tnum"
- android:textSize="@dimen/tv_volume_number_text_size"
- android:textColor="@color/accent_tint_color_selector"/>
+ android:tint="@color/accent_tint_color_selector"
+ android:soundEffectsEnabled="false" />
</LinearLayout>
<include layout="@layout/volume_dnd_icon"/>
diff --git a/packages/SystemUI/res/values-land-television/dimens.xml b/packages/SystemUI/res/values-land-television/dimens.xml
index 90fc652b05e9..8237919990de 100644
--- a/packages/SystemUI/res/values-land-television/dimens.xml
+++ b/packages/SystemUI/res/values-land-television/dimens.xml
@@ -15,8 +15,9 @@
-->
<resources>
- <!-- Width of volume bar -->
- <dimen name="volume_dialog_row_width">252dp</dimen>
+ <!-- Height of volume bar -->
+ <dimen name="volume_dialog_row_height">200dp</dimen>
+ <dimen name="volume_dialog_panel_transparent_padding">17dp</dimen>
<dimen name="tv_volume_dialog_bubble_size">36dp</dimen>
<dimen name="tv_volume_dialog_corner_radius">40dp</dimen>
<dimen name="tv_volume_dialog_row_padding">5dp</dimen>
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
index b2d057b4bcd8..4a94038f4533 100644
--- a/packages/SystemUI/res/values-television/config.xml
+++ b/packages/SystemUI/res/values-television/config.xml
@@ -33,7 +33,6 @@
<item>com.android.systemui.power.PowerUI</item>
<item>com.android.systemui.media.RingtonePlayer</item>
<item>com.android.systemui.keyboard.KeyboardUI</item>
- <item>com.android.systemui.pip.PipUI</item>
<item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
<item>@string/config_systemUIVendorServiceComponent</item>
<item>com.android.systemui.SliceBroadcastRelayHandler</item>
diff --git a/packages/SystemUI/res/values-television/integers.xml b/packages/SystemUI/res/values-television/integers.xml
index 91e83ccbbe79..587497edfdfb 100644
--- a/packages/SystemUI/res/values-television/integers.xml
+++ b/packages/SystemUI/res/values-television/integers.xml
@@ -17,6 +17,7 @@
<resources>
<!-- The position of the volume dialog on the screen.
See com.android.systemui.volume.VolumeDialogImpl.
- Value 81 corresponds to BOTTOM|CENTER_HORIZONTAL. -->
- <integer name="volume_dialog_gravity">81</integer>
-</resources> \ No newline at end of file
+ Value 81 corresponds to BOTTOM|CENTER_HORIZONTAL.
+ Value 21 corresponds to RIGHT|CENTER_VERTICAL. -->
+ <integer name="volume_dialog_gravity">21</integer>
+</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 130bb4fc90b9..7faa2a44bb6c 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -306,7 +306,6 @@
<item>com.android.systemui.power.PowerUI</item>
<item>com.android.systemui.media.RingtonePlayer</item>
<item>com.android.systemui.keyboard.KeyboardUI</item>
- <item>com.android.systemui.pip.PipUI</item>
<item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
<item>@string/config_systemUIVendorServiceComponent</item>
<item>com.android.systemui.util.leak.GarbageMonitor$Service</item>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index c354241da7b4..1027329b8d3c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -2519,13 +2519,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
if (isUserUnlocked(getCurrentUser())) {
return false;
}
- Intent homeIntent = new Intent(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_HOME);
- ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(homeIntent,
- 0 /* flags */);
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME);
+ ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivityAsUser(homeIntent,
+ 0 /* flags */, getCurrentUser());
- // TODO(b/160971249): Replace in the future by resolving activity as user.
- if (resolveInfo == null && mIsAutomotive) {
+ if (resolveInfo == null) {
Log.w(TAG, "resolveNeedsSlowUnlockTransition: returning false since activity "
+ "could not be resolved.");
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 17b840cc7a20..744a77f5cff9 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -32,10 +32,10 @@ import android.view.View;
import android.view.ViewConfiguration;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.policy.ScrollAdapter;
+import com.android.wm.shell.animation.FlingAnimationUtils;
public class ExpandHelper implements Gefingerpoken {
public interface Callback {
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index e91284b546db..8aa3493cc105 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -37,8 +37,8 @@ import android.view.accessibility.AccessibilityEvent;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.wm.shell.animation.FlingAnimationUtils;
public class SwipeHelper implements Gefingerpoken {
static final String TAG = "com.android.systemui.SwipeHelper";
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 2622593880ba..4bea0674e8bf 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -22,7 +22,6 @@ import com.android.systemui.InitController;
import com.android.systemui.SystemUIAppComponentFactory;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardSliceProvider;
-import com.android.systemui.pip.phone.dagger.PipModule;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.InjectionInflationController;
@@ -36,7 +35,6 @@ import dagger.Subcomponent;
@Subcomponent(modules = {
DefaultComponentBinder.class,
DependencyProvider.class,
- PipModule.class,
SystemUIBinder.class,
SystemUIModule.class,
SystemUIDefaultModule.class})
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 9dfd9f8fd9bf..c331bd377eec 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -29,7 +29,6 @@ import com.android.systemui.globalactions.GlobalActionsComponent;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.dagger.KeyguardModule;
import com.android.systemui.onehanded.OneHandedUI;
-import com.android.systemui.pip.PipUI;
import com.android.systemui.power.PowerUI;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsModule;
@@ -97,12 +96,6 @@ public abstract class SystemUIBinder {
@ClassKey(OneHandedUI.class)
public abstract SystemUI bindOneHandedUI(OneHandedUI sysui);
- /** Inject into PipUI. */
- @Binds
- @IntoMap
- @ClassKey(PipUI.class)
- public abstract SystemUI bindPipUI(PipUI sysui);
-
/** Inject into PowerUI. */
@Binds
@IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 686531acb6f9..b2ad19b5f42f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -562,7 +562,10 @@ class MediaDataManager(
decoder, info, source -> decoder.isMutableRequired = true
}
} catch (e: IOException) {
- e.printStackTrace()
+ Log.e(TAG, "Unable to load bitmap", e)
+ null
+ } catch (e: RuntimeException) {
+ Log.e(TAG, "Unable to load bitmap", e)
null
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java b/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
deleted file mode 100644
index 38744fe1b670..000000000000
--- a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2017 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.pip;
-
-import android.content.res.Configuration;
-
-import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
-
-import java.io.PrintWriter;
-
-
-public interface BasePipManager {
- void showPictureInPictureMenu();
- default void expandPip() {}
- default void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {}
- void onConfigurationChanged(Configuration newConfig);
- default void setShelfHeight(boolean visible, int height) {}
- default void setPinnedStackAnimationType(int animationType) {}
- default void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) {}
- default void dump(PrintWriter pw) {}
-}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/Pip.java b/packages/SystemUI/src/com/android/systemui/pip/Pip.java
new file mode 100644
index 000000000000..b068370da9e3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/Pip.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2017 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.pip;
+
+import android.content.res.Configuration;
+import android.media.session.MediaController;
+
+import com.android.systemui.pip.tv.PipController;
+import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
+
+import java.io.PrintWriter;
+
+/**
+ * Interface to engage picture in picture feature.
+ */
+public interface Pip {
+ /**
+ * Called when showing Pip menu.
+ */
+ void showPictureInPictureMenu();
+
+ /**
+ * Registers {@link com.android.systemui.pip.tv.PipController.Listener} that gets called.
+ * whenever receiving notification on changes in PIP.
+ */
+ default void addListener(PipController.Listener listener) {
+ }
+
+ /**
+ * Registers a {@link com.android.systemui.pip.tv.PipController.MediaListener} to PipController.
+ */
+ default void addMediaListener(PipController.MediaListener listener) {
+ }
+
+ /**
+ * Closes PIP (PIPed activity and PIP system UI).
+ */
+ default void closePip() {
+ }
+
+ /**
+ * Expand PIP, it's possible that specific request to activate the window via Alt-tab.
+ */
+ default void expandPip() {
+ }
+
+ /**
+ * Get current play back state. (e.g: Used in TV)
+ *
+ * @return The state of defined in PipController.
+ */
+ default int getPlaybackState() {
+ return 0;
+ }
+
+ /**
+ * Get MediaController.
+ *
+ * @return The MediaController instance.
+ */
+ default MediaController getMediaController() {
+ return null;
+ }
+
+ /**
+ * Hides the PIP menu.
+ */
+ void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback);
+
+ /**
+ * Returns {@code true} if PIP is shown.
+ */
+ default boolean isPipShown() {
+ return false;
+ }
+
+ /**
+ * Moves the PIPed activity to the fullscreen and closes PIP system UI.
+ */
+ default void movePipToFullscreen() {
+ }
+
+ /**
+ * Called when configuration change invoked.
+ */
+ void onConfigurationChanged(Configuration newConfig);
+
+ /**
+ * Removes a {@link PipController.Listener} from PipController.
+ */
+ default void removeListener(PipController.Listener listener) {
+ }
+
+ /**
+ * Removes a {@link com.android.systemui.pip.tv.PipController.MediaListener} from PipController.
+ */
+ default void removeMediaListener(PipController.MediaListener listener) {
+ }
+
+ /**
+ * Resize the Pip to the appropriate size for the input state.
+ *
+ * @param state In Pip state also used to determine the new size for the Pip.
+ */
+ default void resizePinnedStack(int state) {
+ }
+
+ /**
+ * Resumes resizing operation on the Pip that was previously suspended.
+ *
+ * @param reason The reason resizing operations on the Pip was suspended.
+ */
+ default void resumePipResizing(int reason) {
+ }
+
+ /**
+ * Sets both shelf visibility and its height.
+ *
+ * @param visible visibility of shelf.
+ * @param height to specify the height for shelf.
+ */
+ default void setShelfHeight(boolean visible, int height) {
+ }
+
+ /**
+ * Set the pinned stack with {@link PipAnimationController.AnimationType}
+ *
+ * @param animationType The pre-defined {@link PipAnimationController.AnimationType}
+ */
+ default void setPinnedStackAnimationType(int animationType) {
+ }
+
+ /**
+ * Registers the pinned stack animation listener.
+ *
+ * @param listener The listener of pinned stack animation.
+ */
+ default void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) {
+ }
+
+ /**
+ * Suspends resizing operation on the Pip until {@link #resumePipResizing} is called.
+ *
+ * @param reason The reason for suspending resizing operations on the Pip.
+ */
+ default void suspendPipResizing(int reason) {
+ }
+
+ /**
+ * Dump the current state and information if need.
+ *
+ * @param pw The stream to dump information to.
+ */
+ default void dump(PrintWriter pw) {
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index c956702c9216..6f44090d2744 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -47,6 +47,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
+import android.util.Rational;
import android.util.Size;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
@@ -684,13 +685,16 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize
* {@link PictureInPictureParams} would affect the bounds.
*/
private boolean applyPictureInPictureParams(@NonNull PictureInPictureParams params) {
- final boolean changed = (mPictureInPictureParams == null) || !Objects.equals(
- mPictureInPictureParams.getAspectRatioRational(), params.getAspectRatioRational());
- if (changed) {
- mPictureInPictureParams = params;
+ final Rational currentAspectRatio =
+ mPictureInPictureParams != null ? mPictureInPictureParams.getAspectRatioRational()
+ : null;
+ final boolean aspectRatioChanged = !Objects.equals(currentAspectRatio,
+ params.getAspectRatioRational());
+ mPictureInPictureParams = params;
+ if (aspectRatioChanged) {
mPipBoundsHandler.onAspectRatioChanged(params.getAspectRatio());
}
- return changed;
+ return aspectRatioChanged;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
deleted file mode 100644
index 2cd1e202125d..000000000000
--- a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2016 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.pip;
-
-import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.os.UserHandle;
-import android.os.UserManager;
-
-import com.android.systemui.SystemUI;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
-import com.android.systemui.statusbar.CommandQueue;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-import javax.inject.Inject;
-
-/**
- * Controls the picture-in-picture window.
- */
-@SysUISingleton
-public class PipUI extends SystemUI implements CommandQueue.Callbacks {
-
- private final CommandQueue mCommandQueue;
- private BasePipManager mPipManager;
-
- @Inject
- public PipUI(Context context, CommandQueue commandQueue,
- BasePipManager pipManager) {
- super(context);
- mCommandQueue = commandQueue;
- mPipManager = pipManager;
- }
-
- @Override
- public void start() {
- PackageManager pm = mContext.getPackageManager();
- boolean supportsPip = pm.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
- if (!supportsPip) {
- return;
- }
-
- // Ensure that we are the primary user's SystemUI.
- final int processUser = UserManager.get(mContext).getUserHandle();
- if (processUser != UserHandle.USER_SYSTEM) {
- throw new IllegalStateException("Non-primary Pip component not currently supported.");
- }
-
- mCommandQueue.addCallback(this);
- }
-
- @Override
- public void showPictureInPictureMenu() {
- mPipManager.showPictureInPictureMenu();
- }
-
- public void expandPip() {
- mPipManager.expandPip();
- }
-
- public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {
- mPipManager.hidePipMenu(onStartCallback, onEndCallback);
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- if (mPipManager == null) {
- return;
- }
-
- mPipManager.onConfigurationChanged(newConfig);
- }
-
- public void setShelfHeight(boolean visible, int height) {
- if (mPipManager == null) {
- return;
- }
-
- mPipManager.setShelfHeight(visible, height);
- }
-
- public void setPinnedStackAnimationType(int animationType) {
- if (mPipManager != null) {
- mPipManager.setPinnedStackAnimationType(animationType);
- }
- }
-
- public void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) {
- if (mPipManager != null) {
- mPipManager.setPinnedStackAnimationListener(listener);
- }
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mPipManager == null) {
- return;
- }
-
- mPipManager.dump(pw);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java
index 5ef5b902327e..6998e90b3a7c 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java
@@ -18,6 +18,7 @@ package com.android.systemui.pip.phone;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static com.android.systemui.pip.PipAnimationController.isOutPipDirection;
@@ -28,11 +29,14 @@ import android.app.IActivityManager;
import android.app.RemoteAction;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.util.Log;
import android.util.Pair;
import android.view.DisplayInfo;
@@ -44,7 +48,7 @@ import com.android.systemui.UiOffloadThread;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.model.SysUiState;
-import com.android.systemui.pip.BasePipManager;
+import com.android.systemui.pip.Pip;
import com.android.systemui.pip.PipBoundsHandler;
import com.android.systemui.pip.PipSurfaceTransactionHelper;
import com.android.systemui.pip.PipTaskOrganizer;
@@ -55,25 +59,20 @@ import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.WindowManagerWrapper;
-import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.FloatingContentCoordinator;
-import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
import java.io.PrintWriter;
-import java.util.Optional;
-
-import javax.inject.Inject;
/**
* Manages the picture-in-picture (PIP) UI and states for Phones.
*/
@SysUISingleton
-public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitionCallback {
- private static final String TAG = "PipManager";
+public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallback {
+ private static final String TAG = "PipController";
private Context mContext;
private IActivityManager mActivityManager;
@@ -87,15 +86,15 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
private DisplayController mDisplayController;
private InputConsumerController mInputConsumerController;
private PipAppOpsListener mAppOpsListener;
+ private PipBoundsHandler mPipBoundsHandler;
private PipMediaController mMediaController;
private PipTouchHandler mTouchHandler;
- private PipTaskOrganizer mPipTaskOrganizer;
private PipSurfaceTransactionHelper mPipSurfaceTransactionHelper;
private IPinnedStackAnimationListener mPinnedStackAnimationRecentsListener;
private boolean mIsInFixedRotation;
- protected PipBoundsHandler mPipBoundsHandler;
protected PipMenuActivityController mMenuController;
+ protected PipTaskOrganizer mPipTaskOrganizer;
/**
* Handler for display rotation changes.
@@ -127,7 +126,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
// not during the fixed rotation. In fixed rotation case, app is about to enter PiP
// and we need the offsets preserved to calculate the destination bounds.
if (!mIsInFixedRotation) {
- mPipBoundsHandler.setShelfHeight(false , 0);
+ mPipBoundsHandler.setShelfHeight(false, 0);
mPipBoundsHandler.onImeVisibilityChanged(false, 0);
mTouchHandler.onShelfVisibilityChanged(false, 0);
mTouchHandler.onImeVisibilityChanged(false, 0);
@@ -201,7 +200,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
/**
* Handler for messages from the PIP controller.
*/
- private class PipManagerPinnedStackListener extends PinnedStackListener {
+ private class PipControllerPinnedStackListener extends PinnedStackListener {
@Override
public void onListenerRegistered(IPinnedStackController controller) {
mHandler.post(() -> mTouchHandler.setPinnedStackController(controller));
@@ -253,44 +252,56 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
public ConfigurationController.ConfigurationListener mOverlayChangedListener =
new ConfigurationController.ConfigurationListener() {
- @Override
- public void onOverlayChanged() {
- mHandler.post(() -> {
- mPipBoundsHandler.onOverlayChanged(mContext, mContext.getDisplay());
- updateMovementBounds(null /* toBounds */,
- false /* fromRotation */, false /* fromImeAdjustment */,
- false /* fromShelfAdjustment */, null /* windowContainerTransaction */);
- });
- }
- };
+ @Override
+ public void onOverlayChanged() {
+ mHandler.post(() -> {
+ mPipBoundsHandler.onOverlayChanged(mContext, mContext.getDisplay());
+ updateMovementBounds(null /* toBounds */,
+ false /* fromRotation */, false /* fromImeAdjustment */,
+ false /* fromShelfAdjustment */,
+ null /* windowContainerTransaction */);
+ });
+ }
+ };
- @Inject
- public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
+ public PipController(Context context, BroadcastDispatcher broadcastDispatcher,
ConfigurationController configController,
DeviceConfigProxy deviceConfig,
DisplayController displayController,
- Optional<SplitScreen> splitScreenOptional,
FloatingContentCoordinator floatingContentCoordinator,
SysUiState sysUiState,
- PipUiEventLogger pipUiEventLogger,
- ShellTaskOrganizer shellTaskOrganizer) {
+ PipBoundsHandler pipBoundsHandler,
+ PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ PipTaskOrganizer pipTaskOrganizer,
+ PipUiEventLogger pipUiEventLogger) {
mContext = context;
mActivityManager = ActivityManager.getService();
+ PackageManager pm = context.getPackageManager();
+ boolean supportsPip = pm.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
+ if (!supportsPip) {
+ Log.w(TAG, "Device not support PIP feature");
+ return;
+ }
+
+ // Ensure that we are the primary user's SystemUI.
+ final int processUser = UserManager.get(context).getUserHandle();
+ if (processUser != UserHandle.USER_SYSTEM) {
+ throw new IllegalStateException("Non-primary Pip component not currently supported.");
+ }
+
try {
WindowManagerWrapper.getInstance().addPinnedStackListener(
- new PipManagerPinnedStackListener());
+ new PipControllerPinnedStackListener());
} catch (RemoteException e) {
Log.e(TAG, "Failed to register pinned stack listener", e);
}
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
mDisplayController = displayController;
- mPipBoundsHandler = new PipBoundsHandler(mContext);
- mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(context, configController);
- mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler,
- mPipSurfaceTransactionHelper, splitScreenOptional, mDisplayController,
- pipUiEventLogger, shellTaskOrganizer);
+ mPipBoundsHandler = pipBoundsHandler;
+ mPipSurfaceTransactionHelper = pipSurfaceTransactionHelper;
+ mPipTaskOrganizer = pipTaskOrganizer;
mPipTaskOrganizer.registerPipTransitionCallback(this);
mInputConsumerController = InputConsumerController.getPipInputConsumer();
mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher);
@@ -450,6 +461,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
mTmpDisplayInfo.rotation);
}
+ @Override
public void dump(PrintWriter pw) {
final String innerPrefix = " ";
pw.println(TAG);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
index f6853ecf8ee7..50d20d3572d1 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
@@ -329,6 +329,10 @@ public class PipResizeGestureHandler {
mInputMonitor.pilferPointers();
}
if (mThresholdCrossed) {
+ if (mPipMenuActivityController.isMenuVisible()) {
+ mPipMenuActivityController.hideMenuWithoutResize();
+ mPipMenuActivityController.hideMenu();
+ }
final Rect currentPipBounds = mMotionHelper.getBounds();
mLastResizeBounds.set(TaskResizingAlgorithm.resizeDrag(x, y,
mDownPoint.x, mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x,
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipModule.java b/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipModule.java
deleted file mode 100644
index c8b6982a2eba..000000000000
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipModule.java
+++ /dev/null
@@ -1,34 +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 com.android.systemui.pip.phone.dagger;
-
-import com.android.systemui.pip.BasePipManager;
-import com.android.systemui.pip.phone.PipManager;
-
-import dagger.Binds;
-import dagger.Module;
-
-/**
- * Dagger Module for Phone PIP.
- */
-@Module
-public abstract class PipModule {
-
- /** Binds PipManager as the default BasePipManager. */
- @Binds
- public abstract BasePipManager providePipManager(PipManager pipManager);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java
index a388fa324a2e..3b3235f1e63c 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java
@@ -20,7 +20,6 @@ import static android.app.ActivityTaskManager.INVALID_STACK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import android.annotation.NonNull;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityTaskManager;
@@ -51,35 +50,32 @@ import com.android.systemui.R;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.pip.BasePipManager;
+import com.android.systemui.pip.Pip;
import com.android.systemui.pip.PipBoundsHandler;
import com.android.systemui.pip.PipSurfaceTransactionHelper;
import com.android.systemui.pip.PipTaskOrganizer;
-import com.android.systemui.pip.PipUiEventLogger;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.WindowManagerWrapper;
-import com.android.systemui.stackdivider.SplitScreen;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.DisplayController;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
-import javax.inject.Inject;
-
/**
* Manages the picture-in-picture (PIP) UI and states.
*/
@SysUISingleton
-public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitionCallback {
- private static final String TAG = "PipManager";
+public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallback {
+ private static final String TAG = "PipController";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
/**
+ * Unknown or invalid state
+ */
+ public static final int STATE_UNKNOWN = -1;
+ /**
* State when there's no PIP.
*/
public static final int STATE_NO_PIP = 0;
@@ -147,7 +143,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
private boolean mImeVisible;
private int mImeHeightAdjustment;
- private final PinnedStackListener mPinnedStackListener = new PipManagerPinnedStackListener();
+ private final PinnedStackListener mPinnedStackListener = new PipControllerPinnedStackListener();
private final Runnable mResizePinnedStackRunnable = new Runnable() {
@Override
@@ -189,7 +185,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
/**
* Handler for messages from the PIP controller.
*/
- private class PipManagerPinnedStackListener extends PinnedStackListener {
+ private class PipControllerPinnedStackListener extends PinnedStackListener {
@Override
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
mHandler.post(() -> {
@@ -231,20 +227,19 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
}
}
- @Inject
- public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
- ConfigurationController configController,
- DisplayController displayController,
- Optional<SplitScreen> splitScreenOptional,
- @NonNull PipUiEventLogger pipUiEventLogger,
- ShellTaskOrganizer shellTaskOrganizer) {
+ public PipController(Context context, BroadcastDispatcher broadcastDispatcher,
+ PipBoundsHandler pipBoundsHandler,
+ PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ PipTaskOrganizer pipTaskOrganizer) {
if (mInitialized) {
return;
}
mInitialized = true;
mContext = context;
- mPipBoundsHandler = new PipBoundsHandler(mContext);
+ mPipNotification = new PipNotification(context, broadcastDispatcher,
+ Optional.of(this).get());
+ mPipBoundsHandler = pipBoundsHandler;
// Ensure that we have the display info in case we get calls to update the bounds before the
// listener calls back
final DisplayInfo displayInfo = new DisplayInfo();
@@ -253,10 +248,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
mResizeAnimationDuration = context.getResources()
.getInteger(R.integer.config_pipResizeAnimationDuration);
- mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(context, configController);
- mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler,
- mPipSurfaceTransactionHelper, splitScreenOptional, displayController,
- pipUiEventLogger, shellTaskOrganizer);
+ mPipSurfaceTransactionHelper = pipSurfaceTransactionHelper;
+ mPipTaskOrganizer = pipTaskOrganizer;
mPipTaskOrganizer.registerPipTransitionCallback(this);
mActivityTaskManager = ActivityTaskManager.getService();
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
@@ -278,8 +271,6 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
} catch (RemoteException | UnsupportedOperationException e) {
Log.e(TAG, "Failed to register pinned stack listener", e);
}
-
- mPipNotification = new PipNotification(context, broadcastDispatcher, this);
}
private void loadConfigurationsAndApply(Configuration newConfig) {
@@ -359,7 +350,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
/**
* Moves the PIPed activity to the fullscreen and closes PIP system UI.
*/
- void movePipToFullscreen() {
+ public void movePipToFullscreen() {
if (DEBUG) Log.d(TAG, "movePipToFullscreen(), current state=" + getStateDescription());
mPipTaskId = TASK_ID_NO_PIP;
@@ -372,34 +363,41 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
/**
* Suspends resizing operation on the Pip until {@link #resumePipResizing} is called
+ *
* @param reason The reason for suspending resizing operations on the Pip.
*/
public void suspendPipResizing(int reason) {
- if (DEBUG) Log.d(TAG,
- "suspendPipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
+ if (DEBUG) {
+ Log.d(TAG,
+ "suspendPipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
+ }
mSuspendPipResizingReason |= reason;
}
/**
* Resumes resizing operation on the Pip that was previously suspended.
+ *
* @param reason The reason resizing operations on the Pip was suspended.
*/
public void resumePipResizing(int reason) {
if ((mSuspendPipResizingReason & reason) == 0) {
return;
}
- if (DEBUG) Log.d(TAG,
- "resumePipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
+ if (DEBUG) {
+ Log.d(TAG,
+ "resumePipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
+ }
mSuspendPipResizingReason &= ~reason;
mHandler.post(mResizePinnedStackRunnable);
}
/**
* Resize the Pip to the appropriate size for the input state.
+ *
* @param state In Pip state also used to determine the new size for the Pip.
*/
- void resizePinnedStack(int state) {
+ public void resizePinnedStack(int state) {
if (DEBUG) {
Log.d(TAG, "resizePinnedStack() state=" + stateToName(state) + ", current state="
+ getStateDescription(), new Exception());
@@ -411,10 +409,12 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
}
if (mSuspendPipResizingReason != 0) {
mResumeResizePinnedStackRunnableState = state;
- if (DEBUG) Log.d(TAG, "resizePinnedStack() deferring"
- + " mSuspendPipResizingReason=" + mSuspendPipResizingReason
- + " mResumeResizePinnedStackRunnableState="
- + stateToName(mResumeResizePinnedStackRunnableState));
+ if (DEBUG) {
+ Log.d(TAG, "resizePinnedStack() deferring"
+ + " mSuspendPipResizingReason=" + mSuspendPipResizingReason
+ + " mResumeResizePinnedStackRunnableState="
+ + stateToName(mResumeResizePinnedStackRunnableState));
+ }
return;
}
mState = state;
@@ -471,28 +471,28 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
}
/**
- * Adds a {@link Listener} to PipManager.
+ * Adds a {@link Listener} to PipController.
*/
public void addListener(Listener listener) {
mListeners.add(listener);
}
/**
- * Removes a {@link Listener} from PipManager.
+ * Removes a {@link Listener} from PipController.
*/
public void removeListener(Listener listener) {
mListeners.remove(listener);
}
/**
- * Adds a {@link MediaListener} to PipManager.
+ * Adds a {@link MediaListener} to PipController.
*/
public void addMediaListener(MediaListener listener) {
mMediaListeners.add(listener);
}
/**
- * Removes a {@link MediaListener} from PipManager.
+ * Removes a {@link MediaListener} from PipController.
*/
public void removeMediaListener(MediaListener listener) {
mMediaListeners.remove(listener);
@@ -568,16 +568,21 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
/**
* Gets the {@link android.media.session.MediaController} for the PIPed activity.
*/
- MediaController getMediaController() {
+ public MediaController getMediaController() {
return mPipMediaController;
}
+ @Override
+ public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {
+
+ }
+
/**
* Returns the PIPed activity's playback state.
* This returns one of {@link #PLAYBACK_STATE_PLAYING}, {@link #PLAYBACK_STATE_PAUSED},
* or {@link #PLAYBACK_STATE_UNAVAILABLE}.
*/
- int getPlaybackState() {
+ public int getPlaybackState() {
if (mPipMediaController == null || mPipMediaController.getPlaybackState() == null) {
return PLAYBACK_STATE_UNAVAILABLE;
}
@@ -673,7 +678,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
};
@Override
- public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) { }
+ public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) {
+ }
@Override
public void onPipTransitionFinished(ComponentName activity, int direction) {
@@ -701,7 +707,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
* Invoked when an activity is pinned and PIP manager is set corresponding information.
* Classes must use this instead of {@link android.app.ITaskStackListener.onActivityPinned}
* because there's no guarantee for the PIP manager be return relavent information
- * correctly. (e.g. {@link isPipShown}).
+ * correctly. (e.g. {@link Pip.isPipShown}).
*/
void onPipEntered(String packageName);
/** Invoked when a PIPed activity is closed. */
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java
index 05bb882ea52e..4ecd52f8adf5 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java
@@ -27,12 +27,14 @@ import android.view.LayoutInflater;
import android.view.View;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.pip.Pip;
import com.android.wm.shell.R;
import java.util.ArrayList;
import java.util.List;
-
-import javax.inject.Inject;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
/**
* Controller for {@link PipControlsView}.
@@ -43,9 +45,9 @@ public class PipControlsViewController {
private static final float DISABLED_ACTION_ALPHA = 0.54f;
private final PipControlsView mView;
- private final PipManager mPipManager;
private final LayoutInflater mLayoutInflater;
private final Handler mHandler;
+ private final Optional<Pip> mPipOptional;
private final PipControlButtonView mPlayPauseButtonView;
private MediaController mMediaController;
private PipControlButtonView mFocusedChild;
@@ -73,12 +75,14 @@ public class PipControlsViewController {
@Override
public void onViewAttachedToWindow(View v) {
updateMediaController();
- mPipManager.addMediaListener(mPipMediaListener);
+ mPipOptional.ifPresent(
+ pip -> pip.addMediaListener(mPipMediaListener));
}
@Override
public void onViewDetachedFromWindow(View v) {
- mPipManager.removeMediaListener(mPipMediaListener);
+ mPipOptional.ifPresent(
+ pip -> pip.removeMediaListener(mPipMediaListener));
}
};
@@ -89,7 +93,7 @@ public class PipControlsViewController {
}
};
- private final PipManager.MediaListener mPipMediaListener = this::updateMediaController;
+ private final PipController.MediaListener mPipMediaListener = this::updateMediaController;
private final View.OnFocusChangeListener
mFocusChangeListener =
@@ -105,12 +109,11 @@ public class PipControlsViewController {
};
- @Inject
- public PipControlsViewController(PipControlsView view, PipManager pipManager,
+ public PipControlsViewController(PipControlsView view, Optional<Pip> pipOptional,
LayoutInflater layoutInflater, @Main Handler handler) {
super();
mView = view;
- mPipManager = pipManager;
+ mPipOptional = pipOptional;
mLayoutInflater = layoutInflater;
mHandler = handler;
@@ -121,12 +124,14 @@ public class PipControlsViewController {
View fullButtonView = mView.getFullButtonView();
fullButtonView.setOnFocusChangeListener(mFocusChangeListener);
- fullButtonView.setOnClickListener(v -> mPipManager.movePipToFullscreen());
+ fullButtonView.setOnClickListener(
+ v -> mPipOptional.ifPresent(pip -> pip.movePipToFullscreen())
+ );
View closeButtonView = mView.getCloseButtonView();
closeButtonView.setOnFocusChangeListener(mFocusChangeListener);
closeButtonView.setOnClickListener(v -> {
- mPipManager.closePip();
+ mPipOptional.ifPresent(pip -> pip.closePip());
if (mListener != null) {
mListener.onClosed();
}
@@ -139,24 +144,29 @@ public class PipControlsViewController {
if (mMediaController == null || mMediaController.getPlaybackState() == null) {
return;
}
- if (mPipManager.getPlaybackState() == PipManager.PLAYBACK_STATE_PAUSED) {
- mMediaController.getTransportControls().play();
- } else if (mPipManager.getPlaybackState() == PipManager.PLAYBACK_STATE_PLAYING) {
- mMediaController.getTransportControls().pause();
- }
+ mPipOptional.ifPresent(pip -> {
+ if (pip.getPlaybackState() == PipController.PLAYBACK_STATE_PAUSED) {
+ mMediaController.getTransportControls().play();
+ } else if (pip.getPlaybackState() == PipController.PLAYBACK_STATE_PLAYING) {
+ mMediaController.getTransportControls().pause();
+ }
+ });
+
// View will be updated later in {@link mMediaControllerCallback}
});
}
private void updateMediaController() {
- MediaController newController = mPipManager.getMediaController();
- if (mMediaController == newController) {
+ AtomicReference<MediaController> newController = new AtomicReference<>();
+ mPipOptional.ifPresent(pip -> newController.set(pip.getMediaController()));
+
+ if (newController.get() == null || mMediaController == newController.get()) {
return;
}
if (mMediaController != null) {
mMediaController.unregisterCallback(mMediaControllerCallback);
}
- mMediaController = newController;
+ mMediaController = newController.get();
if (mMediaController != null) {
mMediaController.registerCallback(mMediaControllerCallback);
}
@@ -210,12 +220,14 @@ public class PipControlsViewController {
// Hide the media session buttons
mPlayPauseButtonView.setVisibility(View.GONE);
} else {
- int state = mPipManager.getPlaybackState();
- if (state == PipManager.PLAYBACK_STATE_UNAVAILABLE) {
+ AtomicInteger state = new AtomicInteger(PipController.STATE_UNKNOWN);
+ mPipOptional.ifPresent(pip -> state.set(pip.getPlaybackState()));
+ if (state.get() == PipController.STATE_UNKNOWN
+ || state.get() == PipController.PLAYBACK_STATE_UNAVAILABLE) {
mPlayPauseButtonView.setVisibility(View.GONE);
} else {
mPlayPauseButtonView.setVisibility(View.VISIBLE);
- if (state == PipManager.PLAYBACK_STATE_PLAYING) {
+ if (state.get() == PipController.PLAYBACK_STATE_PLAYING) {
mPlayPauseButtonView.setImageResource(R.drawable.pip_ic_pause_white);
mPlayPauseButtonView.setText(R.string.pip_pause);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
index 70374036ef14..7e812d9ca8a1 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
@@ -25,17 +25,20 @@ import android.content.pm.ParceledListSlice;
import android.os.Bundle;
import android.util.Log;
+import com.android.systemui.pip.Pip;
import com.android.systemui.pip.tv.dagger.TvPipComponent;
import com.android.wm.shell.R;
import java.util.Collections;
+import java.util.Optional;
import javax.inject.Inject;
/**
* Activity to show the PIP menu to control PIP.
*/
-public class PipMenuActivity extends Activity implements PipManager.Listener {
+
+public class PipMenuActivity extends Activity implements PipController.Listener {
private static final String TAG = "PipMenuActivity";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -43,7 +46,7 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
private final TvPipComponent.Builder mPipComponentBuilder;
private TvPipComponent mTvPipComponent;
- private final PipManager mPipManager;
+ private final Optional<Pip> mPipOptional;
private Animator mFadeInAnimation;
private Animator mFadeOutAnimation;
@@ -51,10 +54,11 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
private PipControlsViewController mPipControlsViewController;
@Inject
- public PipMenuActivity(TvPipComponent.Builder pipComponentBuilder, PipManager pipManager) {
+ public PipMenuActivity(TvPipComponent.Builder pipComponentBuilder,
+ Optional<Pip> pipOptional) {
super();
mPipComponentBuilder = pipComponentBuilder;
- mPipManager = pipManager;
+ mPipOptional = pipOptional;
}
@Override
@@ -62,15 +66,17 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
if (DEBUG) Log.d(TAG, "onCreate()");
super.onCreate(bundle);
- if (!mPipManager.isPipShown()) {
- finish();
- }
+ mPipOptional.ifPresent(pip -> {
+ if (!pip.isPipShown()) {
+ finish();
+ }
+ });
setContentView(R.layout.tv_pip_menu);
mTvPipComponent = mPipComponentBuilder.pipControlsView(
findViewById(R.id.pip_controls)).build();
mPipControlsViewController = mTvPipComponent.getPipControlsViewController();
- mPipManager.addListener(this);
+ mPipOptional.ifPresent(pip -> pip.addListener(this));
mRestorePipSizeWhenClose = true;
mFadeInAnimation = AnimatorInflater.loadAnimator(
@@ -98,7 +104,7 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
if (DEBUG) Log.d(TAG, " > restoring to the default position");
// When PIP menu activity is closed, restore to the default position.
- mPipManager.resizePinnedStack(PipManager.STATE_PIP);
+ mPipOptional.ifPresent(pip -> pip.resizePinnedStack(PipController.STATE_PIP));
}
finish();
}
@@ -125,9 +131,9 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
if (DEBUG) Log.d(TAG, "onDestroy()");
super.onDestroy();
- mPipManager.removeListener(this);
- mPipManager.resumePipResizing(
- PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
+ mPipOptional.ifPresent(pip -> pip.removeListener(this));
+ mPipOptional.ifPresent(pip -> pip.resumePipResizing(
+ PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH));
}
@Override
@@ -178,8 +184,8 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
if (DEBUG) Log.d(TAG, "onPipResizeAboutToStart()");
finish();
- mPipManager.suspendPipResizing(
- PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
+ mPipOptional.ifPresent(pip -> pip.suspendPipResizing(
+ PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
index 5e5de58da2f6..78569edf009d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
@@ -48,14 +48,14 @@ import com.android.wm.shell.R;
public class PipNotification {
private static final String TAG = "PipNotification";
private static final String NOTIFICATION_TAG = PipNotification.class.getSimpleName();
- private static final boolean DEBUG = PipManager.DEBUG;
+ private static final boolean DEBUG = PipController.DEBUG;
private static final String ACTION_MENU = "PipNotification.menu";
private static final String ACTION_CLOSE = "PipNotification.close";
private final PackageManager mPackageManager;
- private final PipManager mPipManager;
+ private final PipController mPipController;
private final NotificationManager mNotificationManager;
private final Notification.Builder mNotificationBuilder;
@@ -70,7 +70,7 @@ public class PipNotification {
private String mMediaTitle;
private Bitmap mArt;
- private PipManager.Listener mPipListener = new PipManager.Listener() {
+ private PipController.Listener mPipListener = new PipController.Listener() {
@Override
public void onPipEntered(String packageName) {
mPackageName = packageName;
@@ -124,26 +124,27 @@ public class PipNotification {
}
};
- private final PipManager.MediaListener mPipMediaListener = new PipManager.MediaListener() {
- @Override
- public void onMediaControllerChanged() {
- MediaController newController = mPipManager.getMediaController();
- if (mMediaController == newController) {
- return;
- }
- if (mMediaController != null) {
- mMediaController.unregisterCallback(mMediaControllerCallback);
- }
- mMediaController = newController;
- if (mMediaController != null) {
- mMediaController.registerCallback(mMediaControllerCallback);
- }
- if (updateMediaControllerMetadata() && mNotified) {
- // update notification
- notifyPipNotification();
- }
- }
- };
+ private final PipController.MediaListener mPipMediaListener =
+ new PipController.MediaListener() {
+ @Override
+ public void onMediaControllerChanged() {
+ MediaController newController = mPipController.getMediaController();
+ if (newController == null || mMediaController == newController) {
+ return;
+ }
+ if (mMediaController != null) {
+ mMediaController.unregisterCallback(mMediaControllerCallback);
+ }
+ mMediaController = newController;
+ if (mMediaController != null) {
+ mMediaController.registerCallback(mMediaControllerCallback);
+ }
+ if (updateMediaControllerMetadata() && mNotified) {
+ // update notification
+ notifyPipNotification();
+ }
+ }
+ };
private final BroadcastReceiver mEventReceiver = new BroadcastReceiver() {
@Override
@@ -153,17 +154,17 @@ public class PipNotification {
}
switch (intent.getAction()) {
case ACTION_MENU:
- mPipManager.showPictureInPictureMenu();
+ mPipController.showPictureInPictureMenu();
break;
case ACTION_CLOSE:
- mPipManager.closePip();
+ mPipController.closePip();
break;
}
}
};
public PipNotification(Context context, BroadcastDispatcher broadcastDispatcher,
- PipManager pipManager) {
+ PipController pipController) {
mPackageManager = context.getPackageManager();
mNotificationManager = (NotificationManager) context.getSystemService(
@@ -177,9 +178,9 @@ public class PipNotification {
.setContentIntent(createPendingIntent(context, ACTION_MENU))
.setDeleteIntent(createPendingIntent(context, ACTION_CLOSE)));
- mPipManager = pipManager;
- mPipManager.addListener(mPipListener);
- mPipManager.addMediaListener(mPipMediaListener);
+ mPipController = pipController;
+ pipController.addListener(mPipListener);
+ pipController.addMediaListener(mPipMediaListener);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_MENU);
@@ -190,7 +191,7 @@ public class PipNotification {
}
/**
- * Called by {@link PipManager} when the configuration is changed.
+ * Called by {@link PipController} when the configuration is changed.
*/
void onConfigurationChanged(Context context) {
Resources res = context.getResources();
@@ -227,8 +228,8 @@ public class PipNotification {
private boolean updateMediaControllerMetadata() {
String title = null;
Bitmap art = null;
- if (mPipManager.getMediaController() != null) {
- MediaMetadata metadata = mPipManager.getMediaController().getMetadata();
+ if (mPipController.getMediaController() != null) {
+ MediaMetadata metadata = mPipController.getMediaController().getMetadata();
if (metadata != null) {
title = metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE);
if (TextUtils.isEmpty(title)) {
@@ -248,6 +249,7 @@ public class PipNotification {
return false;
}
+
private String getNotificationTitle() {
if (!TextUtils.isEmpty(mMediaTitle)) {
return mMediaTitle;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/PipModule.java b/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/PipModule.java
deleted file mode 100644
index 52b38a91a58f..000000000000
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/PipModule.java
+++ /dev/null
@@ -1,46 +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 com.android.systemui.pip.tv.dagger;
-
-import android.app.Activity;
-
-import com.android.systemui.pip.BasePipManager;
-import com.android.systemui.pip.tv.PipManager;
-import com.android.systemui.pip.tv.PipMenuActivity;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.IntoMap;
-
-/**
- * Dagger module for TV Pip.
- */
-@Module(subcomponents = {TvPipComponent.class})
-public abstract class PipModule {
-
- /** Binds PipManager as the default BasePipManager. */
- @Binds
- public abstract BasePipManager providePipManager(PipManager pipManager);
-
-
- /** Inject into PipMenuActivity. */
- @Binds
- @IntoMap
- @ClassKey(PipMenuActivity.class)
- public abstract Activity providePipMenuActivity(PipMenuActivity activity);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index b4f1fe72f944..5e6a6ce45b46 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -130,7 +130,8 @@ public class CellularTile extends QSTileImpl<SignalState> {
return;
}
String carrierName = mController.getMobileDataNetworkName();
- if (TextUtils.isEmpty(carrierName)) {
+ boolean isInService = mController.isMobileDataNetworkInService();
+ if (TextUtils.isEmpty(carrierName) || !isInService) {
carrierName = mContext.getString(R.string.mobile_data_disable_message_default_carrier);
}
AlertDialog dialog = new Builder(mContext)
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 263bbdbf7c35..56f010d7e866 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -16,6 +16,7 @@
package com.android.systemui.recents;
+import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
@@ -75,8 +76,8 @@ import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.onehanded.OneHandedUI;
+import com.android.systemui.pip.Pip;
import com.android.systemui.pip.PipAnimationController;
-import com.android.systemui.pip.PipUI;
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.shared.recents.IOverviewProxy;
@@ -122,7 +123,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
private static final long MAX_BACKOFF_MILLIS = 10 * 60 * 1000;
private final Context mContext;
- private final PipUI mPipUI;
+ private final Optional<Pip> mPipOptional;
private final Optional<Lazy<StatusBar>> mStatusBarOptionalLazy;
private final Optional<SplitScreen> mSplitScreenOptional;
private SysUiState mSysUiState;
@@ -143,6 +144,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
private int mConnectionBackoffAttempts;
private boolean mBound;
private boolean mIsEnabled;
+ private boolean mHasPipFeature;
private int mCurrentBoundedUserId = -1;
private float mNavBarButtonAlpha;
private boolean mInputFocusTransferStarted;
@@ -383,12 +385,15 @@ public class OverviewProxyService extends CurrentUserTracker implements
@Override
public void setShelfHeight(boolean visible, int shelfHeight) {
- if (!verifyCaller("setShelfHeight")) {
+ if (!verifyCaller("setShelfHeight") || !mHasPipFeature) {
+ Log.w(TAG_OPS,
+ "ByPass setShelfHeight, FEATURE_PICTURE_IN_PICTURE:" + mHasPipFeature);
return;
}
long token = Binder.clearCallingIdentity();
try {
- mPipUI.setShelfHeight(visible, shelfHeight);
+ mPipOptional.ifPresent(
+ pip -> pip.setShelfHeight(visible, shelfHeight));
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -408,12 +413,16 @@ public class OverviewProxyService extends CurrentUserTracker implements
@Override
public void notifySwipeToHomeFinished() {
- if (!verifyCaller("notifySwipeToHomeFinished")) {
+ if (!verifyCaller("notifySwipeToHomeFinished") || !mHasPipFeature) {
+ Log.w(TAG_OPS, "ByPass notifySwipeToHomeFinished, FEATURE_PICTURE_IN_PICTURE:"
+ + mHasPipFeature);
return;
}
long token = Binder.clearCallingIdentity();
try {
- mPipUI.setPinnedStackAnimationType(PipAnimationController.ANIM_TYPE_ALPHA);
+ mPipOptional.ifPresent(
+ pip -> pip.setPinnedStackAnimationType(
+ PipAnimationController.ANIM_TYPE_ALPHA));
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -421,12 +430,15 @@ public class OverviewProxyService extends CurrentUserTracker implements
@Override
public void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) {
- if (!verifyCaller("setPinnedStackAnimationListener")) {
+ if (!verifyCaller("setPinnedStackAnimationListener") || !mHasPipFeature) {
+ Log.w(TAG_OPS, "ByPass setPinnedStackAnimationListener, FEATURE_PICTURE_IN_PICTURE:"
+ + mHasPipFeature);
return;
}
long token = Binder.clearCallingIdentity();
try {
- mPipUI.setPinnedStackAnimationListener(listener);
+ mPipOptional.ifPresent(
+ pip -> pip.setPinnedStackAnimationListener(listener));
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -603,14 +615,17 @@ public class OverviewProxyService extends CurrentUserTracker implements
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Inject
public OverviewProxyService(Context context, CommandQueue commandQueue,
- Lazy<NavigationBarController> navBarControllerLazy, NavigationModeController navModeController,
+ Lazy<NavigationBarController> navBarControllerLazy,
+ NavigationModeController navModeController,
NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
- PipUI pipUI, Optional<SplitScreen> splitScreenOptional,
+ Optional<Pip> pipOptional,
+ Optional<SplitScreen> splitScreenOptional,
Optional<Lazy<StatusBar>> statusBarOptionalLazy, OneHandedUI oneHandedUI,
BroadcastDispatcher broadcastDispatcher) {
super(broadcastDispatcher);
mContext = context;
- mPipUI = pipUI;
+ mPipOptional = pipOptional;
+ mHasPipFeature = mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
mStatusBarOptionalLazy = statusBarOptionalLazy;
mHandler = new Handler();
mNavBarControllerLazy = navBarControllerLazy;
@@ -916,6 +931,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
/**
* Notifies the Launcher of split screen size changes
+ *
* @param secondaryWindowBounds Bounds of the secondary window including the insets
* @param secondaryWindowInsets stable insets received by the secondary window
*/
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
index a10242a689a2..1559169bd8ca 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
@@ -28,8 +28,8 @@ import android.util.AttributeSet;
import android.util.Property;
import android.view.View;
-import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.wm.shell.animation.Interpolators;
/**
* View for the handle in the docked stack divider.
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index fdf24b1e1a7e..9bf7ea681926 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -62,9 +62,9 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.internal.policy.DockedDividerUtils;
-import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.statusbar.FlingAnimationUtils;
+import com.android.wm.shell.animation.FlingAnimationUtils;
+import com.android.wm.shell.animation.Interpolators;
import java.util.function.Consumer;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 2c296353bd14..4b9d5924a8d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -40,6 +40,7 @@ import android.widget.ImageView;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.wm.shell.animation.FlingAnimationUtils;
/**
* An ImageView which does not have overlapping renderings commands and therefore does not need a
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index ba9420265849..5dfb22faee7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -29,8 +29,8 @@ import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.KeyguardAffordanceView;
+import com.android.wm.shell.animation.FlingAnimationUtils;
/**
* A touch handler of the keyguard which is responsible for launching phone and camera affordances.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index f62783502e5b..cd9cc0775c66 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -86,7 +86,6 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.qs.QSFragment;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -123,6 +122,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.util.InjectionInflationController;
+import com.android.wm.shell.animation.FlingAnimationUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 0e72506c6d94..6fa99ba41006 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -48,12 +48,12 @@ import com.android.systemui.R;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.wm.shell.animation.FlingAnimationUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index cf83603997c0..eb2d9bce6c4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -418,6 +418,10 @@ public class MobileSignalController extends SignalController<
return (mServiceState != null && mServiceState.isEmergencyOnly());
}
+ public boolean isInService() {
+ return Utils.isInService(mServiceState);
+ }
+
private boolean isRoaming() {
// During a carrier change, roaming indications need to be supressed.
if (isCarrierNetworkChangeActive()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index b790c92b293c..8722fecdad96 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -35,6 +35,7 @@ public interface NetworkController extends CallbackController<SignalCallback>, D
DataUsageController getMobileDataController();
DataSaverController getDataSaverController();
String getMobileDataNetworkName();
+ boolean isMobileDataNetworkInService();
int getNumberSubscriptions();
boolean hasVoiceCallingFeature();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 2253ce7a62a3..62b922e23532 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -460,6 +460,12 @@ public class NetworkControllerImpl extends BroadcastReceiver
}
@Override
+ public boolean isMobileDataNetworkInService() {
+ MobileSignalController controller = getDataController();
+ return controller != null && controller.isInService();
+ }
+
+ @Override
public int getNumberSubscriptions() {
return mMobileSignalControllers.size();
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
index 9a44bf12a3ef..22fa0106795a 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
@@ -17,12 +17,11 @@
package com.android.systemui.tv;
import com.android.systemui.dagger.GlobalRootComponent;
-import com.android.systemui.pip.tv.dagger.PipModule;
import dagger.Binds;
import dagger.Module;
-@Module(includes = {PipModule.class})
+@Module()
interface TvSystemUIBinder {
@Binds
GlobalRootComponent bindGlobalRootComponent(TvGlobalRootComponent globalRootComponent);
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index d727bfbdf48a..c5bb9c1b6f48 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -62,7 +62,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.wmshell.WMShellModule;
+import com.android.systemui.wmshell.TvWMShellModule;
import javax.inject.Named;
@@ -76,7 +76,7 @@ import dagger.Provides;
*/
@Module(includes = {
QSModule.class,
- WMShellModule.class
+ TvWMShellModule.class,
},
subcomponents = {
})
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
new file mode 100644
index 000000000000..d8cb280bc7e0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
@@ -0,0 +1,108 @@
+/*
+ * 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.wmshell;
+
+import android.content.Context;
+import android.os.Handler;
+import android.view.IWindowManager;
+
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.pip.Pip;
+import com.android.systemui.pip.PipBoundsHandler;
+import com.android.systemui.pip.PipSurfaceTransactionHelper;
+import com.android.systemui.pip.PipTaskOrganizer;
+import com.android.systemui.pip.PipUiEventLogger;
+import com.android.systemui.pip.tv.PipController;
+import com.android.systemui.pip.tv.PipNotification;
+import com.android.systemui.pip.tv.dagger.TvPipComponent;
+import com.android.systemui.stackdivider.SplitScreen;
+import com.android.systemui.stackdivider.SplitScreenController;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TransactionPool;
+
+import java.util.Optional;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Provides dependencies from {@link com.android.wm.shell} which could be customized among different
+ * branches of SystemUI.
+ */
+// TODO(b/162923491): Move most of these dependencies into WMSingleton scope.
+@Module(includes = WMShellBaseModule.class, subcomponents = {TvPipComponent.class})
+public class TvWMShellModule {
+ @SysUISingleton
+ @Provides
+ static DisplayImeController provideDisplayImeController(IWindowManager wmService,
+ DisplayController displayController, @Main Handler mainHandler,
+ TransactionPool transactionPool) {
+ return new DisplayImeController(wmService, displayController, mainHandler, transactionPool);
+ }
+
+ @SysUISingleton
+ @Provides
+ static Pip providePipController(Context context,
+ BroadcastDispatcher broadcastDispatcher,
+ PipBoundsHandler pipBoundsHandler,
+ PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ PipTaskOrganizer pipTaskOrganizer) {
+ return new PipController(context, broadcastDispatcher, pipBoundsHandler,
+ pipSurfaceTransactionHelper, pipTaskOrganizer);
+ }
+
+ @SysUISingleton
+ @Provides
+ static SplitScreen provideSplitScreen(Context context,
+ DisplayController displayController, SystemWindows systemWindows,
+ DisplayImeController displayImeController, @Main Handler handler,
+ TransactionPool transactionPool, ShellTaskOrganizer shellTaskOrganizer) {
+ return new SplitScreenController(context, displayController, systemWindows,
+ displayImeController, handler, transactionPool, shellTaskOrganizer);
+ }
+
+ @SysUISingleton
+ @Provides
+ static PipNotification providePipNotification(Context context,
+ BroadcastDispatcher broadcastDispatcher,
+ PipController pipController) {
+ return new PipNotification(context, broadcastDispatcher, pipController);
+ }
+
+ @SysUISingleton
+ @Provides
+ static PipBoundsHandler providesPipBoundsHandler(Context context) {
+ return new PipBoundsHandler(context);
+ }
+
+ @SysUISingleton
+ @Provides
+ static PipTaskOrganizer providesPipTaskOrganizer(Context context,
+ PipBoundsHandler pipBoundsHandler,
+ PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ Optional<SplitScreen> splitScreenOptional, DisplayController displayController,
+ PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) {
+ return new PipTaskOrganizer(context, pipBoundsHandler,
+ pipSurfaceTransactionHelper, splitScreenOptional, displayController,
+ pipUiEventLogger, shellTaskOrganizer);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index ee404ca980b2..27af5f91c9e4 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -21,14 +21,17 @@ import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_
import android.app.ActivityManager;
import android.content.Context;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.pip.Pip;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.tracing.ProtoTraceable;
import com.android.systemui.stackdivider.SplitScreen;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.tracing.nano.SystemUiTraceProto;
import com.android.wm.shell.common.DisplayImeController;
@@ -47,19 +50,28 @@ import javax.inject.Inject;
*/
@SysUISingleton
public final class WMShell extends SystemUI implements ProtoTraceable<SystemUiTraceProto> {
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final CommandQueue mCommandQueue;
private final DisplayImeController mDisplayImeController;
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final ActivityManagerWrapper mActivityManagerWrapper;
+ private final Optional<Pip> mPipOptional;
private final Optional<SplitScreen> mSplitScreenOptional;
private final ProtoTracer mProtoTracer;
@Inject
- WMShell(Context context, KeyguardUpdateMonitor keyguardUpdateMonitor,
+ public WMShell(Context context, CommandQueue commandQueue,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ ActivityManagerWrapper activityManagerWrapper,
DisplayImeController displayImeController,
+ Optional<Pip> pipOptional,
Optional<SplitScreen> splitScreenOptional,
ProtoTracer protoTracer) {
super(context);
+ mCommandQueue = commandQueue;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mActivityManagerWrapper = activityManagerWrapper;
mDisplayImeController = displayImeController;
+ mPipOptional = pipOptional;
mSplitScreenOptional = splitScreenOptional;
mProtoTracer = protoTracer;
mProtoTracer.add(this);
@@ -72,10 +84,22 @@ public final class WMShell extends SystemUI implements ProtoTraceable<SystemUiTr
// specific feature anymore.
mDisplayImeController.startMonitorDisplays();
+ mPipOptional.ifPresent(this::initPip);
mSplitScreenOptional.ifPresent(this::initSplitScreen);
}
- private void initSplitScreen(SplitScreen splitScreen) {
+ @VisibleForTesting
+ void initPip(Pip pip) {
+ mCommandQueue.addCallback(new CommandQueue.Callbacks() {
+ @Override
+ public void showPictureInPictureMenu() {
+ pip.showPictureInPictureMenu();
+ }
+ });
+ }
+
+ @VisibleForTesting
+ void initSplitScreen(SplitScreen splitScreen) {
mKeyguardUpdateMonitor.registerCallback(new KeyguardUpdateMonitorCallback() {
@Override
public void onKeyguardVisibilityChanged(boolean showing) {
@@ -87,7 +111,7 @@ public final class WMShell extends SystemUI implements ProtoTraceable<SystemUiTr
}
});
- ActivityManagerWrapper.getInstance().registerTaskStackListener(
+ mActivityManagerWrapper.registerTaskStackListener(
new TaskStackChangeListener() {
@Override
public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 0a3172ce4eb6..e63c6c317392 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -18,16 +18,21 @@ package com.android.systemui.wmshell;
import android.content.Context;
import android.os.Handler;
+import android.util.DisplayMetrics;
import android.view.IWindowManager;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.pip.Pip;
+import com.android.systemui.pip.PipSurfaceTransactionHelper;
import com.android.systemui.pip.PipUiEventLogger;
import com.android.systemui.stackdivider.SplitScreen;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.FloatingContentCoordinator;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.animation.FlingAnimationUtils;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TransactionPool;
@@ -76,6 +81,13 @@ public abstract class WMShellBaseModule {
@SysUISingleton
@Provides
+ static PipSurfaceTransactionHelper providesPipSurfaceTransactionHelper(Context context,
+ ConfigurationController configController) {
+ return new PipSurfaceTransactionHelper(context, configController);
+ }
+
+ @SysUISingleton
+ @Provides
static SystemWindows provideSystemWindows(DisplayController displayController,
IWindowManager wmService) {
return new SystemWindows(displayController, wmService);
@@ -90,5 +102,15 @@ public abstract class WMShellBaseModule {
}
@BindsOptionalOf
+ abstract Pip optionalPip();
+
+ @BindsOptionalOf
abstract SplitScreen optionalSplitScreen();
+
+ @SysUISingleton
+ @Provides
+ static FlingAnimationUtils.Builder provideFlingAnimationUtilsBuilder(
+ DisplayMetrics displayMetrics) {
+ return new FlingAnimationUtils.Builder(displayMetrics);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 6a2ca44bfc17..1870b7605567 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -20,16 +20,29 @@ import android.content.Context;
import android.os.Handler;
import android.view.IWindowManager;
+import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.pip.Pip;
+import com.android.systemui.pip.PipBoundsHandler;
+import com.android.systemui.pip.PipSurfaceTransactionHelper;
+import com.android.systemui.pip.PipTaskOrganizer;
+import com.android.systemui.pip.PipUiEventLogger;
+import com.android.systemui.pip.phone.PipController;
import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.stackdivider.SplitScreenController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.util.DeviceConfigProxy;
+import com.android.systemui.util.FloatingContentCoordinator;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TransactionPool;
+import java.util.Optional;
+
import dagger.Module;
import dagger.Provides;
@@ -50,6 +63,26 @@ public class WMShellModule {
@SysUISingleton
@Provides
+ static Pip providePipController(Context context,
+ BroadcastDispatcher broadcastDispatcher,
+ ConfigurationController configController,
+ DeviceConfigProxy deviceConfig,
+ DisplayController displayController,
+ FloatingContentCoordinator floatingContentCoordinator,
+ SysUiState sysUiState,
+ PipBoundsHandler pipBoundsHandler,
+ PipSurfaceTransactionHelper surfaceTransactionHelper,
+ PipTaskOrganizer pipTaskOrganizer,
+ PipUiEventLogger pipUiEventLogger) {
+ return new PipController(context, broadcastDispatcher, configController, deviceConfig,
+ displayController, floatingContentCoordinator, sysUiState, pipBoundsHandler,
+ surfaceTransactionHelper,
+ pipTaskOrganizer,
+ pipUiEventLogger);
+ }
+
+ @SysUISingleton
+ @Provides
static SplitScreen provideSplitScreen(Context context,
DisplayController displayController, SystemWindows systemWindows,
DisplayImeController displayImeController, @Main Handler handler,
@@ -57,4 +90,23 @@ public class WMShellModule {
return new SplitScreenController(context, displayController, systemWindows,
displayImeController, handler, transactionPool, shellTaskOrganizer);
}
+
+ @SysUISingleton
+ @Provides
+ static PipBoundsHandler providesPipBoundsHandler(Context context) {
+ return new PipBoundsHandler(context);
+ }
+
+ @SysUISingleton
+ @Provides
+ static PipTaskOrganizer providesPipTaskOrganizer(Context context,
+ PipBoundsHandler pipBoundsHandler,
+ PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ Optional<SplitScreen> splitScreenOptional, DisplayController displayController,
+ PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) {
+ return new PipTaskOrganizer(context, pipBoundsHandler,
+ pipSurfaceTransactionHelper, splitScreenOptional, displayController,
+ pipUiEventLogger, shellTaskOrganizer);
+ }
+
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
index 8089561f44a0..b0f2a8902870 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
@@ -38,6 +38,7 @@ import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -70,6 +71,7 @@ public class NonPhoneDependencyTest extends SysuiTestCase {
new Handler(TestableLooper.get(this).getLooper()));
}
+ @Ignore("Causes binder calls which fail")
@Test
public void testNotificationManagementCodeHasNoDependencyOnStatusBarWindowManager() {
mDependency.injectMockDependency(ShadeController.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index cf64ff2f8cd6..7ee27c9a8aab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -62,7 +62,6 @@ import com.android.systemui.doze.DozeLog;
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShelfController;
@@ -81,6 +80,7 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.InjectionInflationController;
+import com.android.wm.shell.animation.FlingAnimationUtils;
import org.junit.Before;
import org.junit.Test;
@@ -192,8 +192,6 @@ public class NotificationPanelViewTest extends SysuiTestCase {
@Mock
private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
- private FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder;
-
private NotificationPanelViewController mNotificationPanelViewController;
private View.AccessibilityDelegate mAccessibiltyDelegate;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index d8aa29e9f766..68992179de59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -3,6 +3,8 @@ package com.android.systemui.statusbar.policy;
import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -10,6 +12,7 @@ import static org.mockito.Mockito.when;
import android.net.NetworkCapabilities;
import android.os.Looper;
import android.telephony.NetworkRegistrationInfo;
+import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -259,6 +262,25 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest {
assertDataNetworkNameEquals(newDataName);
}
+ @Test
+ public void testIsDataInService_true() {
+ setupDefaultSignal();
+ assertTrue(mNetworkController.isMobileDataNetworkInService());
+ }
+
+ @Test
+ public void testIsDataInService_noSignal_false() {
+ assertFalse(mNetworkController.isMobileDataNetworkInService());
+ }
+
+ @Test
+ public void testIsDataInService_notInService_false() {
+ setupDefaultSignal();
+ setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE);
+ setDataRegState(ServiceState.STATE_OUT_OF_SERVICE);
+ assertFalse(mNetworkController.isMobileDataNetworkInService());
+ }
+
private void testDataActivity(int direction, boolean in, boolean out) {
updateDataActivity(direction);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
index d5ba381bfcac..e7acfae24f30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeNetworkController.java
@@ -95,6 +95,11 @@ public class FakeNetworkController extends BaseLeakChecker<SignalCallback>
}
@Override
+ public boolean isMobileDataNetworkInService() {
+ return false;
+ }
+
+ @Override
public int getNumberSubscriptions() {
return 0;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
new file mode 100644
index 000000000000..ac9346f675be
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.wmshell;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.pip.Pip;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.stackdivider.SplitScreen;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.tracing.ProtoTracer;
+import com.android.wm.shell.common.DisplayImeController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Optional;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WMShellTest extends SysuiTestCase {
+
+ WMShell mWMShell;
+ @Mock CommandQueue mCommandQueue;
+ @Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock ActivityManagerWrapper mActivityManagerWrapper;
+ @Mock DisplayImeController mDisplayImeController;
+ @Mock Pip mPip;
+ @Mock SplitScreen mSplitScreen;
+ @Mock ProtoTracer mProtoTracer;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mWMShell = new WMShell(mContext, mCommandQueue, mKeyguardUpdateMonitor,
+ mActivityManagerWrapper, mDisplayImeController, Optional.of(mPip),
+ Optional.of(mSplitScreen), mProtoTracer);
+ }
+
+ @Test
+ public void start_startsMonitorDisplays() {
+ mWMShell.start();
+
+ verify(mDisplayImeController).startMonitorDisplays();
+ }
+
+ @Test
+ public void initPip_registersCommandQueueCallback() {
+ mWMShell.initPip(mPip);
+
+ verify(mCommandQueue).addCallback(any(CommandQueue.Callbacks.class));
+ }
+
+ @Test
+ public void initSplitScreen_registersCallbacks() {
+ mWMShell.initSplitScreen(mSplitScreen);
+
+ verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.class));
+ verify(mActivityManagerWrapper).registerTaskStackListener(
+ any(TaskStackChangeListener.class));
+ }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
index c70dfcc93e49..df4a52e308b6 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
@@ -287,7 +287,9 @@ class EventDispatcher {
/**
* Sends down events to the view hierarchy for all pointers which are not already being
- * delivered with original down location. i.e. pointers that are not yet injected.
+ * delivered with original down location. i.e. pointers that are not yet injected. The down time
+ * is also replaced by the original one.
+ *
*
* @param prototype The prototype from which to create the injected events.
* @param policyFlags The policy flags associated with the event.
@@ -296,7 +298,7 @@ class EventDispatcher {
// Inject the injected pointers.
int pointerIdBits = 0;
final int pointerCount = prototype.getPointerCount();
- final MotionEvent event = computeEventWithOriginalDown(prototype);
+ final MotionEvent event = computeInjectionDownEvent(prototype);
for (int i = 0; i < pointerCount; i++) {
final int pointerId = prototype.getPointerId(i);
// Do not send event for already delivered pointers.
@@ -313,7 +315,7 @@ class EventDispatcher {
}
}
- private MotionEvent computeEventWithOriginalDown(MotionEvent prototype) {
+ private MotionEvent computeInjectionDownEvent(MotionEvent prototype) {
final int pointerCount = prototype.getPointerCount();
if (pointerCount != mState.getReceivedPointerTracker().getReceivedPointerDownCount()) {
Slog.w(LOG_TAG, "The pointer count doesn't match the received count.");
@@ -336,7 +338,10 @@ class EventDispatcher {
MotionEvent event =
MotionEvent.obtain(
prototype.getDownTime(),
- prototype.getEventTime(),
+ // The event time is used for downTime while sending ACTION_DOWN. We adjust
+ // it to avoid the motion velocity is too fast in the beginning after
+ // Delegating.
+ prototype.getDownTime(),
prototype.getAction(),
pointerCount,
properties,
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index f56b0b5578f7..7b9728cb4f08 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -393,12 +393,14 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
.toString());
long identity = Binder.clearCallingIdentity();
try {
- return PendingIntent.getActivity(getContext(),
+ return PendingIntent.getActivityAsUser(getContext(),
0 /* request code */,
NotificationAccessConfirmationActivityContract.launcherIntent(
userId, component, packageTitle),
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT
- | PendingIntent.FLAG_CANCEL_CURRENT);
+ | PendingIntent.FLAG_CANCEL_CURRENT,
+ null /* options */,
+ new UserHandle(userId));
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b15273a2bd70..a5d2011483bc 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5762,9 +5762,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
private boolean isAppBad(final String processName, final int uid) {
- synchronized (this) {
- return mAppErrors.isBadProcessLocked(processName, uid);
- }
+ return mAppErrors.isBadProcess(processName, uid);
}
// NOTE: this is an internal method used by the OnShellCommand implementation only and should
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 5268359df327..5d429d3065f3 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -50,6 +50,7 @@ import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.ProcessMap;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
@@ -96,7 +97,11 @@ class AppErrors {
* a minimum amount of time; they are removed from it when they are
* later restarted (hopefully due to some user action). The value is the
* time it was added to the list.
+ *
+ * Access is synchronized on the container object itself, and no other
+ * locks may be acquired while holding that one.
*/
+ @GuardedBy("mBadProcesses")
private final ProcessMap<BadProcessInfo> mBadProcesses = new ProcessMap<>();
@@ -114,76 +119,81 @@ class AppErrors {
mProcessCrashTimes.clear();
mProcessCrashTimesPersistent.clear();
mProcessCrashShowDialogTimes.clear();
- mBadProcesses.clear();
+ synchronized (mBadProcesses) {
+ mBadProcesses.clear();
+ }
}
void dumpDebug(ProtoOutputStream proto, long fieldId, String dumpPackage) {
- if (mProcessCrashTimes.getMap().isEmpty() && mBadProcesses.getMap().isEmpty()) {
- return;
- }
-
- final long token = proto.start(fieldId);
- final long now = SystemClock.uptimeMillis();
- proto.write(AppErrorsProto.NOW_UPTIME_MS, now);
-
- if (!mProcessCrashTimes.getMap().isEmpty()) {
- final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
- final int procCount = pmap.size();
- for (int ip = 0; ip < procCount; ip++) {
- final long ctoken = proto.start(AppErrorsProto.PROCESS_CRASH_TIMES);
- final String pname = pmap.keyAt(ip);
- final SparseArray<Long> uids = pmap.valueAt(ip);
- final int uidCount = uids.size();
+ synchronized (mBadProcesses) {
+ if (mProcessCrashTimes.getMap().isEmpty() && mBadProcesses.getMap().isEmpty()) {
+ return;
+ }
- proto.write(AppErrorsProto.ProcessCrashTime.PROCESS_NAME, pname);
- for (int i = 0; i < uidCount; i++) {
- final int puid = uids.keyAt(i);
- final ProcessRecord r = mService.getProcessNames().get(pname, puid);
- if (dumpPackage != null && (r == null || !r.pkgList.containsKey(dumpPackage))) {
- continue;
+ final long token = proto.start(fieldId);
+ final long now = SystemClock.uptimeMillis();
+ proto.write(AppErrorsProto.NOW_UPTIME_MS, now);
+
+ if (!mProcessCrashTimes.getMap().isEmpty()) {
+ final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
+ final int procCount = pmap.size();
+ for (int ip = 0; ip < procCount; ip++) {
+ final long ctoken = proto.start(AppErrorsProto.PROCESS_CRASH_TIMES);
+ final String pname = pmap.keyAt(ip);
+ final SparseArray<Long> uids = pmap.valueAt(ip);
+ final int uidCount = uids.size();
+
+ proto.write(AppErrorsProto.ProcessCrashTime.PROCESS_NAME, pname);
+ for (int i = 0; i < uidCount; i++) {
+ final int puid = uids.keyAt(i);
+ final ProcessRecord r = mService.getProcessNames().get(pname, puid);
+ if (dumpPackage != null
+ && (r == null || !r.pkgList.containsKey(dumpPackage))) {
+ continue;
+ }
+ final long etoken = proto.start(AppErrorsProto.ProcessCrashTime.ENTRIES);
+ proto.write(AppErrorsProto.ProcessCrashTime.Entry.UID, puid);
+ proto.write(AppErrorsProto.ProcessCrashTime.Entry.LAST_CRASHED_AT_MS,
+ uids.valueAt(i));
+ proto.end(etoken);
}
- final long etoken = proto.start(AppErrorsProto.ProcessCrashTime.ENTRIES);
- proto.write(AppErrorsProto.ProcessCrashTime.Entry.UID, puid);
- proto.write(AppErrorsProto.ProcessCrashTime.Entry.LAST_CRASHED_AT_MS,
- uids.valueAt(i));
- proto.end(etoken);
+ proto.end(ctoken);
}
- proto.end(ctoken);
- }
- }
+ }
- if (!mBadProcesses.getMap().isEmpty()) {
- final ArrayMap<String, SparseArray<BadProcessInfo>> pmap = mBadProcesses.getMap();
- final int processCount = pmap.size();
- for (int ip = 0; ip < processCount; ip++) {
- final long btoken = proto.start(AppErrorsProto.BAD_PROCESSES);
- final String pname = pmap.keyAt(ip);
- final SparseArray<BadProcessInfo> uids = pmap.valueAt(ip);
- final int uidCount = uids.size();
+ if (!mBadProcesses.getMap().isEmpty()) {
+ final ArrayMap<String, SparseArray<BadProcessInfo>> pmap = mBadProcesses.getMap();
+ final int processCount = pmap.size();
+ for (int ip = 0; ip < processCount; ip++) {
+ final long btoken = proto.start(AppErrorsProto.BAD_PROCESSES);
+ final String pname = pmap.keyAt(ip);
+ final SparseArray<BadProcessInfo> uids = pmap.valueAt(ip);
+ final int uidCount = uids.size();
- proto.write(AppErrorsProto.BadProcess.PROCESS_NAME, pname);
- for (int i = 0; i < uidCount; i++) {
- final int puid = uids.keyAt(i);
- final ProcessRecord r = mService.getProcessNames().get(pname, puid);
- if (dumpPackage != null && (r == null
- || !r.pkgList.containsKey(dumpPackage))) {
- continue;
+ proto.write(AppErrorsProto.BadProcess.PROCESS_NAME, pname);
+ for (int i = 0; i < uidCount; i++) {
+ final int puid = uids.keyAt(i);
+ final ProcessRecord r = mService.getProcessNames().get(pname, puid);
+ if (dumpPackage != null && (r == null
+ || !r.pkgList.containsKey(dumpPackage))) {
+ continue;
+ }
+ final BadProcessInfo info = uids.valueAt(i);
+ final long etoken = proto.start(AppErrorsProto.BadProcess.ENTRIES);
+ proto.write(AppErrorsProto.BadProcess.Entry.UID, puid);
+ proto.write(AppErrorsProto.BadProcess.Entry.CRASHED_AT_MS, info.time);
+ proto.write(AppErrorsProto.BadProcess.Entry.SHORT_MSG, info.shortMsg);
+ proto.write(AppErrorsProto.BadProcess.Entry.LONG_MSG, info.longMsg);
+ proto.write(AppErrorsProto.BadProcess.Entry.STACK, info.stack);
+ proto.end(etoken);
}
- final BadProcessInfo info = uids.valueAt(i);
- final long etoken = proto.start(AppErrorsProto.BadProcess.ENTRIES);
- proto.write(AppErrorsProto.BadProcess.Entry.UID, puid);
- proto.write(AppErrorsProto.BadProcess.Entry.CRASHED_AT_MS, info.time);
- proto.write(AppErrorsProto.BadProcess.Entry.SHORT_MSG, info.shortMsg);
- proto.write(AppErrorsProto.BadProcess.Entry.LONG_MSG, info.longMsg);
- proto.write(AppErrorsProto.BadProcess.Entry.STACK, info.stack);
- proto.end(etoken);
+ proto.end(btoken);
}
- proto.end(btoken);
}
- }
- proto.end(token);
+ proto.end(token);
+ }
}
boolean dumpLocked(FileDescriptor fd, PrintWriter pw, boolean needSep, String dumpPackage) {
@@ -272,12 +282,16 @@ class AppErrors {
return needSep;
}
- boolean isBadProcessLocked(final String processName, final int uid) {
- return mBadProcesses.get(processName, uid) != null;
+ boolean isBadProcess(final String processName, final int uid) {
+ synchronized (mBadProcesses) {
+ return mBadProcesses.get(processName, uid) != null;
+ }
}
- void clearBadProcessLocked(final String processName, final int uid) {
- mBadProcesses.remove(processName, uid);
+ void clearBadProcess(final String processName, final int uid) {
+ synchronized (mBadProcesses) {
+ mBadProcesses.remove(processName, uid);
+ }
}
void resetProcessCrashTimeLocked(final String processName, final int uid) {
@@ -747,8 +761,10 @@ class AppErrors {
if (!app.isolated) {
// XXX We don't have a way to mark isolated processes
// as bad, since they don't have a peristent identity.
- mBadProcesses.put(app.processName, app.uid,
- new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
+ synchronized (mBadProcesses) {
+ mBadProcesses.put(app.processName, app.uid,
+ new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
+ }
mProcessCrashTimes.remove(app.processName, app.uid);
}
app.bad = true;
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 09ffbffd8d86..cd3e21052efb 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2360,7 +2360,7 @@ public final class ProcessList {
if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
// If we are in the background, then check to see if this process
// is bad. If so, we will just silently fail.
- if (mService.mAppErrors.isBadProcessLocked(processName, info.uid)) {
+ if (mService.mAppErrors.isBadProcess(processName, info.uid)) {
if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
+ "/" + processName);
return null;
@@ -2373,11 +2373,11 @@ public final class ProcessList {
if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
+ "/" + processName);
mService.mAppErrors.resetProcessCrashTimeLocked(processName, info.uid);
- if (mService.mAppErrors.isBadProcessLocked(processName, info.uid)) {
+ if (mService.mAppErrors.isBadProcess(processName, info.uid)) {
EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
UserHandle.getUserId(info.uid), info.uid,
info.processName);
- mService.mAppErrors.clearBadProcessLocked(processName, info.uid);
+ mService.mAppErrors.clearBadProcess(processName, info.uid);
if (app != null) {
app.bad = false;
}
diff --git a/services/core/java/com/android/server/audio/AudioEventLogger.java b/services/core/java/com/android/server/audio/AudioEventLogger.java
index 9ebd75bd0f64..af0e978726e3 100644
--- a/services/core/java/com/android/server/audio/AudioEventLogger.java
+++ b/services/core/java/com/android/server/audio/AudioEventLogger.java
@@ -60,7 +60,36 @@ public class AudioEventLogger {
* @return the same instance of the event
*/
public Event printLog(String tag) {
- Log.i(tag, eventToString());
+ return printLog(ALOGI, tag);
+ }
+
+ public static final int ALOGI = 0;
+ public static final int ALOGE = 1;
+ public static final int ALOGW = 2;
+ public static final int ALOGV = 3;
+
+ /**
+ * Same as {@link #printLog(String)} with a log type
+ * @param type one of {@link #ALOGI}, {@link #ALOGE}, {@link #ALOGV}
+ * @param tag
+ * @return
+ */
+ public Event printLog(int type, String tag) {
+ switch (type) {
+ case ALOGI:
+ Log.i(tag, eventToString());
+ break;
+ case ALOGE:
+ Log.e(tag, eventToString());
+ break;
+ case ALOGW:
+ Log.w(tag, eventToString());
+ break;
+ case ALOGV:
+ default:
+ Log.v(tag, eventToString());
+ break;
+ }
return this;
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 3f29eb5636ea..4378490d19c5 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -26,6 +26,10 @@ import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE;
import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE;
+import static com.android.server.audio.AudioEventLogger.Event.ALOGE;
+import static com.android.server.audio.AudioEventLogger.Event.ALOGI;
+import static com.android.server.audio.AudioEventLogger.Event.ALOGW;
+
import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -287,6 +291,7 @@ public class AudioService extends IAudioService.Stub
private static final int MSG_CHECK_MODE_FOR_UID = 31;
private static final int MSG_STREAM_DEVICES_CHANGED = 32;
private static final int MSG_UPDATE_VOLUME_STATES_FOR_DEVICE = 33;
+ private static final int MSG_REINIT_VOLUMES = 34;
// start of messages handled under wakelock
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
// and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -669,6 +674,7 @@ public class AudioService extends IAudioService.Stub
public AudioService(Context context, AudioSystemAdapter audioSystem,
SystemServerAdapter systemServer) {
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent("AudioService()"));
mContext = context;
mContentResolver = context.getContentResolver();
mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
@@ -888,6 +894,9 @@ public class AudioService extends IAudioService.Stub
mPrescaleAbsoluteVolume[i] = preScale[i];
}
}
+
+ // check on volume initialization
+ checkVolumeRangeInitialization("AudioService()");
}
public void systemReady() {
@@ -1015,11 +1024,15 @@ public class AudioService extends IAudioService.Stub
if (!mSystemReady ||
(AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Log.e(TAG, "Audioserver died.");
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent(
+ "onAudioServerDied() audioserver died"));
sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED, SENDMSG_NOOP, 0, 0,
null, 500);
return;
}
- Log.e(TAG, "Audioserver started.");
+ Log.i(TAG, "Audioserver started.");
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent(
+ "onAudioServerDied() audioserver started"));
updateAudioHalPids();
@@ -1054,14 +1067,7 @@ public class AudioService extends IAudioService.Stub
mDeviceBroker.setForceUse_Async(AudioSystem.FOR_SYSTEM, forSys, "onAudioServerDied");
// Restore stream volumes
- int numStreamTypes = AudioSystem.getNumStreamTypes();
- for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
- VolumeStreamState streamState = mStreamStates[streamType];
- AudioSystem.initStreamVolume(
- streamType, streamState.mIndexMin / 10, streamState.mIndexMax / 10);
-
- streamState.applyAllVolumes();
- }
+ onReinitVolumes("after audioserver restart");
// Restore audio volume groups
restoreVolumeGroups();
@@ -1159,6 +1165,72 @@ public class AudioService extends IAudioService.Stub
setMicMuteFromSwitchInput();
}
+ private void onReinitVolumes(@NonNull String caller) {
+ final int numStreamTypes = AudioSystem.getNumStreamTypes();
+ // keep track of any error during stream volume initialization
+ int status = AudioSystem.AUDIO_STATUS_OK;
+ for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+ VolumeStreamState streamState = mStreamStates[streamType];
+ final int res = AudioSystem.initStreamVolume(
+ streamType, streamState.mIndexMin / 10, streamState.mIndexMax / 10);
+ if (res != AudioSystem.AUDIO_STATUS_OK) {
+ status = res;
+ Log.e(TAG, "Failed to initStreamVolume (" + res + ") for stream " + streamType);
+ // stream volume initialization failed, no need to try the others, it will be
+ // attempted again when MSG_REINIT_VOLUMES is handled
+ break;
+ }
+ streamState.applyAllVolumes();
+ }
+
+ // did it work? check based on status
+ if (status != AudioSystem.AUDIO_STATUS_OK) {
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent(
+ caller + ": initStreamVolume failed with " + status + " will retry")
+ .printLog(ALOGE, TAG));
+ sendMsg(mAudioHandler, MSG_REINIT_VOLUMES, SENDMSG_NOOP, 0, 0,
+ caller /*obj*/, 2 * INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
+ return;
+ }
+
+ // did it work? check based on min/max values of some basic streams
+ if (!checkVolumeRangeInitialization(caller)) {
+ return;
+ }
+
+ // success
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent(
+ caller + ": initStreamVolume succeeded").printLog(ALOGI, TAG));
+ }
+
+ /**
+ * Check volume ranges were properly initialized
+ * @return true if volume ranges were successfully initialized
+ */
+ private boolean checkVolumeRangeInitialization(String caller) {
+ boolean success = true;
+ final int[] basicStreams = { AudioSystem.STREAM_ALARM, AudioSystem.STREAM_RING,
+ AudioSystem.STREAM_MUSIC, AudioSystem.STREAM_VOICE_CALL,
+ AudioSystem.STREAM_ACCESSIBILITY };
+ for (int streamType : basicStreams) {
+ final AudioAttributes aa = new AudioAttributes.Builder()
+ .setInternalLegacyStreamType(streamType).build();
+ if (AudioSystem.getMaxVolumeIndexForAttributes(aa) < 0
+ || AudioSystem.getMinVolumeIndexForAttributes(aa) < 0) {
+ success = false;
+ break;
+ }
+ }
+ if (!success) {
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent(
+ caller + ": initStreamVolume succeeded but invalid mix/max levels, will retry")
+ .printLog(ALOGW, TAG));
+ sendMsg(mAudioHandler, MSG_REINIT_VOLUMES, SENDMSG_NOOP, 0, 0,
+ caller /*obj*/, 2 * INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
+ }
+ return success;
+ }
+
private void onDispatchAudioServerStateChange(boolean state) {
synchronized (mAudioServerStateListeners) {
for (AsdProxy asdp : mAudioServerStateListeners.values()) {
@@ -5672,7 +5744,15 @@ public class AudioService extends IAudioService.Stub
mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;
mIndexMinNoPerm = mIndexMin; // may be overwritten later in updateNoPermMinIndex()
mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;
- AudioSystem.initStreamVolume(streamType, mIndexMin / 10, mIndexMax / 10);
+ final int status = AudioSystem.initStreamVolume(
+ streamType, mIndexMin / 10, mIndexMax / 10);
+ if (status != AudioSystem.AUDIO_STATUS_OK) {
+ sLifecycleLogger.log(new AudioEventLogger.StringEvent(
+ "VSS() stream:" + streamType + " initStreamVolume=" + status)
+ .printLog(ALOGE, TAG));
+ sendMsg(mAudioHandler, MSG_REINIT_VOLUMES, SENDMSG_NOOP, 0, 0,
+ "VSS()" /*obj*/, 2 * INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
+ }
readSettings();
mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
@@ -6543,6 +6623,10 @@ public class AudioService extends IAudioService.Stub
case MSG_UPDATE_VOLUME_STATES_FOR_DEVICE:
onUpdateVolumeStatesForAudioDevice(msg.arg1, (String) msg.obj);
break;
+
+ case MSG_REINIT_VOLUMES:
+ onReinitVolumes((String) msg.obj);
+ break;
}
}
}
@@ -7472,12 +7556,16 @@ public class AudioService extends IAudioService.Stub
//==========================================================================================
// AudioService logging and dumpsys
//==========================================================================================
+ static final int LOG_NB_EVENTS_LIFECYCLE = 20;
static final int LOG_NB_EVENTS_PHONE_STATE = 20;
static final int LOG_NB_EVENTS_DEVICE_CONNECTION = 30;
static final int LOG_NB_EVENTS_FORCE_USE = 20;
static final int LOG_NB_EVENTS_VOLUME = 40;
static final int LOG_NB_EVENTS_DYN_POLICY = 10;
+ static final AudioEventLogger sLifecycleLogger = new AudioEventLogger(LOG_NB_EVENTS_LIFECYCLE,
+ "audio services lifecycle");
+
final private AudioEventLogger mModeLogger = new AudioEventLogger(LOG_NB_EVENTS_PHONE_STATE,
"phone state (logged after successful call to AudioSystem.setPhoneState(int, int))");
@@ -7554,6 +7642,7 @@ public class AudioService extends IAudioService.Stub
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ sLifecycleLogger.dump(pw);
if (mAudioHandler != null) {
pw.println("\nMessage handler (watch for unhandled messages):");
mAudioHandler.dump(new PrintWriterPrinter(pw), " ");
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceAction.java b/services/core/java/com/android/server/hdmi/ActiveSourceAction.java
index c90f297e1485..179602737985 100644
--- a/services/core/java/com/android/server/hdmi/ActiveSourceAction.java
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceAction.java
@@ -51,7 +51,7 @@ public class ActiveSourceAction extends HdmiCecFeatureAction {
Constants.MENU_STATE_ACTIVATED));
}
- source().setActiveSource(logicalAddress, physicalAddress);
+ source().setActiveSource(logicalAddress, physicalAddress, "ActiveSourceAction");
mState = STATE_FINISHED;
finish();
return true;
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
index 01547c16e9b5..8405bbe38b12 100644
--- a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
@@ -17,9 +17,9 @@
package com.android.server.hdmi;
import android.annotation.Nullable;
-import android.hardware.hdmi.IHdmiControlCallback;
-import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.hdmi.IHdmiControlCallback;
import android.os.RemoteException;
import android.util.Slog;
@@ -69,7 +69,7 @@ final class ActiveSourceHandler {
if (!tv.isProhibitMode()) {
ActiveSource old = ActiveSource.of(tv.getActiveSource());
- tv.updateActiveSource(newActive);
+ tv.updateActiveSource(newActive, "ActiveSourceHandler");
boolean notifyInputChange = (mCallback == null);
if (!old.equals(newActive)) {
tv.setPrevPortId(tv.getActivePortId());
@@ -85,7 +85,7 @@ final class ActiveSourceHandler {
HdmiCecMessage activeSourceCommand = HdmiCecMessageBuilder.buildActiveSource(
current.logicalAddress, current.physicalAddress);
mService.sendCecCommand(activeSourceCommand);
- tv.updateActiveSource(current);
+ tv.updateActiveSource(current, "ActiveSourceHandler");
invokeCallback(HdmiControlManager.RESULT_SUCCESS);
} else {
tv.startRoutingControl(newActive.physicalAddress, current.physicalAddress, true,
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 66652ca26e54..7b52ddef29bc 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -688,16 +688,24 @@ final class HdmiCecController {
}
void dump(final IndentingPrintWriter pw) {
+ final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
for (int i = 0; i < mLocalDevices.size(); ++i) {
pw.println("HdmiCecLocalDevice #" + mLocalDevices.keyAt(i) + ":");
pw.increaseIndent();
mLocalDevices.valueAt(i).dump(pw);
+
+ pw.println("Active Source history:");
+ pw.increaseIndent();
+ for (Dumpable activeSourceEvent : mLocalDevices.valueAt(i).getActiveSourceHistory()) {
+ activeSourceEvent.dump(pw, sdf);
+ }
+ pw.decreaseIndent();
pw.decreaseIndent();
}
pw.println("CEC message history:");
pw.increaseIndent();
- final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for (Dumpable record : mMessageHistory) {
record.dump(pw, sdf);
}
@@ -917,7 +925,7 @@ final class HdmiCecController {
}
}
- private abstract static class Dumpable {
+ public abstract static class Dumpable {
protected final long mTime;
Dumpable() {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 86e6a3220507..b88a37e7b8b4 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -38,10 +38,13 @@ import com.android.server.hdmi.Constants.LocalActivePort;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Date;
import java.util.Iterator;
import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
/**
* Class that models a logical CEC device hosted in this system. Handles initialization, CEC
@@ -50,6 +53,7 @@ import java.util.List;
abstract class HdmiCecLocalDevice {
private static final String TAG = "HdmiCecLocalDevice";
+ private static final int MAX_HDMI_ACTIVE_SOURCE_HISTORY = 10;
private static final int MSG_DISABLE_DEVICE_TIMEOUT = 1;
private static final int MSG_USER_CONTROL_RELEASE_TIMEOUT = 2;
// Timeout in millisecond for device clean up (5s).
@@ -68,6 +72,10 @@ abstract class HdmiCecLocalDevice {
protected int mLastKeycode = HdmiCecKeycode.UNSUPPORTED_KEYCODE;
protected int mLastKeyRepeatCount = 0;
+ // Stores recent changes to the active source in the CEC network.
+ private final ArrayBlockingQueue<HdmiCecController.Dumpable> mActiveSourceHistory =
+ new ArrayBlockingQueue<>(MAX_HDMI_ACTIVE_SOURCE_HISTORY);
+
static class ActiveSource {
int logicalAddress;
int physicalAddress;
@@ -893,16 +901,16 @@ abstract class HdmiCecLocalDevice {
return mService.getLocalActiveSource();
}
- void setActiveSource(ActiveSource newActive) {
- setActiveSource(newActive.logicalAddress, newActive.physicalAddress);
+ void setActiveSource(ActiveSource newActive, String caller) {
+ setActiveSource(newActive.logicalAddress, newActive.physicalAddress, caller);
}
- void setActiveSource(HdmiDeviceInfo info) {
- setActiveSource(info.getLogicalAddress(), info.getPhysicalAddress());
+ void setActiveSource(HdmiDeviceInfo info, String caller) {
+ setActiveSource(info.getLogicalAddress(), info.getPhysicalAddress(), caller);
}
- void setActiveSource(int logicalAddress, int physicalAddress) {
- mService.setActiveSource(logicalAddress, physicalAddress);
+ void setActiveSource(int logicalAddress, int physicalAddress, String caller) {
+ mService.setActiveSource(logicalAddress, physicalAddress, caller);
mService.setLastInputForMhl(Constants.INVALID_PORT_ID);
}
@@ -1120,6 +1128,20 @@ abstract class HdmiCecLocalDevice {
HdmiCecMessageBuilder.buildUserControlReleased(mAddress, targetAddress));
}
+ void addActiveSourceHistoryItem(ActiveSource activeSource, boolean isActiveSource,
+ String caller) {
+ ActiveSourceHistoryRecord record = new ActiveSourceHistoryRecord(activeSource,
+ isActiveSource, caller);
+ if (!mActiveSourceHistory.offer(record)) {
+ mActiveSourceHistory.poll();
+ mActiveSourceHistory.offer(record);
+ }
+ }
+
+ public ArrayBlockingQueue<HdmiCecController.Dumpable> getActiveSourceHistory() {
+ return this.mActiveSourceHistory;
+ }
+
/** Dump internal status of HdmiCecLocalDevice object. */
protected void dump(final IndentingPrintWriter pw) {
pw.println("mDeviceType: " + mDeviceType);
@@ -1152,4 +1174,29 @@ abstract class HdmiCecLocalDevice {
}
return finalMask | myPhysicalAddress;
}
+
+ private static final class ActiveSourceHistoryRecord extends HdmiCecController.Dumpable {
+ private final ActiveSource mActiveSource;
+ private final boolean mIsActiveSource;
+ private final String mCaller;
+
+ private ActiveSourceHistoryRecord(ActiveSource mActiveSource, boolean mIsActiveSource,
+ String caller) {
+ this.mActiveSource = mActiveSource;
+ this.mIsActiveSource = mIsActiveSource;
+ this.mCaller = caller;
+ }
+
+ @Override
+ void dump(final IndentingPrintWriter pw, SimpleDateFormat sdf) {
+ pw.print("time=");
+ pw.print(sdf.format(new Date(mTime)));
+ pw.print(" active source=");
+ pw.print(mActiveSource);
+ pw.print(" isActiveSource=");
+ pw.print(mIsActiveSource);
+ pw.print(" from=");
+ pw.println(mCaller);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index af815973d3c3..68473c1830ae 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -361,7 +361,8 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
assertRunOnServiceThread();
// Invalidate the internal active source record when goes to standby
// This set will also update mIsActiveSource
- mService.setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS);
+ mService.setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS,
+ "HdmiCecLocalDeviceAudioSystem#onStandby()");
mTvSystemAudioModeSupport = null;
// Record the last state of System Audio Control before going to standby
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index d675b81629a4..f2f6dbe9bde5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -190,7 +190,8 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
boolean wasActiveSource = mIsActiveSource;
// Invalidate the internal active source record when goes to standby
// This set will also update mIsActiveSource
- mService.setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS);
+ mService.setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS,
+ "HdmiCecLocalDevicePlayback#onStandby()");
if (initiatedByCec || !mAutoTvOff || !wasActiveSource) {
return;
}
@@ -399,7 +400,8 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) {
assertRunOnServiceThread();
if (physicalAddress != mService.getPhysicalAddress()) {
- setActiveSource(physicalAddress);
+ setActiveSource(physicalAddress,
+ "HdmiCecLocalDevicePlayback#handleRoutingChangeAndInformation()");
return;
}
switch (mPlaybackDeviceActionOnRoutingControl) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index 44ad8eea65ca..4ff36c4b65db 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -119,11 +119,11 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
}
@ServiceThreadOnly
- protected void setActiveSource(int physicalAddress) {
+ protected void setActiveSource(int physicalAddress, String caller) {
assertRunOnServiceThread();
// Invalidate the internal active source record. This will also update mIsActiveSource.
ActiveSource activeSource = ActiveSource.of(Constants.ADDR_INVALID, physicalAddress);
- setActiveSource(activeSource);
+ setActiveSource(activeSource, caller);
}
@ServiceThreadOnly
@@ -133,7 +133,7 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress);
if (!getActiveSource().equals(activeSource)) {
- setActiveSource(activeSource);
+ setActiveSource(activeSource, "HdmiCecLocalDeviceSource#handleActiveSource()");
}
setIsActiveSource(physicalAddress == mService.getPhysicalAddress());
updateDevicePowerStatus(logicalAddress, HdmiControlManager.POWER_STATUS_ON);
@@ -162,7 +162,7 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
setAndBroadcastActiveSource(message, physicalAddress);
}
if (physicalAddress != mService.getPhysicalAddress()) {
- setActiveSource(physicalAddress);
+ setActiveSource(physicalAddress, "HdmiCecLocalDeviceSource#handleSetStreamPath()");
}
switchInputOnReceivingNewActivePath(physicalAddress);
return true;
@@ -174,7 +174,7 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
assertRunOnServiceThread();
int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams(), 2);
if (physicalAddress != mService.getPhysicalAddress()) {
- setActiveSource(physicalAddress);
+ setActiveSource(physicalAddress, "HdmiCecLocalDeviceSource#handleRoutingChange()");
}
if (!isRoutingControlFeatureEnabled()) {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
@@ -196,7 +196,7 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
assertRunOnServiceThread();
int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
if (physicalAddress != mService.getPhysicalAddress()) {
- setActiveSource(physicalAddress);
+ setActiveSource(physicalAddress, "HdmiCecLocalDeviceSource#handleRoutingInformation()");
}
if (!isRoutingControlFeatureEnabled()) {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 804cc92cca08..0325ad929849 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -288,13 +288,14 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
if (targetAddress == Constants.ADDR_INTERNAL) {
handleSelectInternalSource();
// Switching to internal source is always successful even when CEC control is disabled.
- setActiveSource(targetAddress, mService.getPhysicalAddress());
+ setActiveSource(targetAddress, mService.getPhysicalAddress(),
+ "HdmiCecLocalDeviceTv#deviceSelect()");
setActivePath(mService.getPhysicalAddress());
invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
return;
}
if (!mService.isControlEnabled()) {
- setActiveSource(targetDevice);
+ setActiveSource(targetDevice, "HdmiCecLocalDeviceTv#deviceSelect()");
invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
return;
}
@@ -307,7 +308,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
assertRunOnServiceThread();
// Seq #18
if (mService.isControlEnabled() && getActiveSource().logicalAddress != mAddress) {
- updateActiveSource(mAddress, mService.getPhysicalAddress());
+ updateActiveSource(mAddress, mService.getPhysicalAddress(),
+ "HdmiCecLocalDeviceTv#handleSelectInternalSource()");
if (mSkipRoutingControl) {
mSkipRoutingControl = false;
return;
@@ -319,19 +321,19 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
}
@ServiceThreadOnly
- void updateActiveSource(int logicalAddress, int physicalAddress) {
+ void updateActiveSource(int logicalAddress, int physicalAddress, String caller) {
assertRunOnServiceThread();
- updateActiveSource(ActiveSource.of(logicalAddress, physicalAddress));
+ updateActiveSource(ActiveSource.of(logicalAddress, physicalAddress), caller);
}
@ServiceThreadOnly
- void updateActiveSource(ActiveSource newActive) {
+ void updateActiveSource(ActiveSource newActive, String caller) {
assertRunOnServiceThread();
// Seq #14
if (getActiveSource().equals(newActive)) {
return;
}
- setActiveSource(newActive);
+ setActiveSource(newActive, caller);
int logicalAddress = newActive.logicalAddress;
if (getCecDeviceInfo(logicalAddress) != null && logicalAddress != mAddress) {
if (mService.pathToPortId(newActive.physicalAddress) == getActivePortId()) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 70ffaae1a9af..44b6a63faea1 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -3228,7 +3228,7 @@ public class HdmiControlService extends SystemService {
}
}
- void setActiveSource(int logicalAddress, int physicalAddress) {
+ void setActiveSource(int logicalAddress, int physicalAddress, String caller) {
synchronized (mLock) {
mActiveSource.logicalAddress = logicalAddress;
mActiveSource.physicalAddress = physicalAddress;
@@ -3239,14 +3239,17 @@ public class HdmiControlService extends SystemService {
// mIsActiveSource only exists in source device, ignore this setting if the current
// device is not an HdmiCecLocalDeviceSource.
if (!(device instanceof HdmiCecLocalDeviceSource)) {
+ device.addActiveSourceHistoryItem(new ActiveSource(logicalAddress, physicalAddress),
+ false, caller);
continue;
}
- if (logicalAddress == device.getDeviceInfo().getLogicalAddress()
- && physicalAddress == getPhysicalAddress()) {
- ((HdmiCecLocalDeviceSource) device).setIsActiveSource(true);
- } else {
- ((HdmiCecLocalDeviceSource) device).setIsActiveSource(false);
- }
+ boolean deviceIsActiveSource =
+ logicalAddress == device.getDeviceInfo().getLogicalAddress()
+ && physicalAddress == getPhysicalAddress();
+
+ ((HdmiCecLocalDeviceSource) device).setIsActiveSource(deviceIsActiveSource);
+ device.addActiveSourceHistoryItem(new ActiveSource(logicalAddress, physicalAddress),
+ deviceIsActiveSource, caller);
}
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index 5c30fe840073..3e5b6e3f462f 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -821,7 +821,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
byte[] data = psdsDownloader.downloadPsdsData(psdsType);
if (data != null) {
if (DEBUG) Log.d(TAG, "calling native_inject_psds_data");
- native_inject_psds_data(data, data.length);
+ native_inject_psds_data(data, data.length, psdsType);
mPsdsBackOff.reset();
}
@@ -2111,7 +2111,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private native boolean native_supports_psds();
- private native void native_inject_psds_data(byte[] data, int length);
+ private native void native_inject_psds_data(byte[] data, int length, int psdsType);
// DEBUG Support
private native String native_get_internal_state();
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 29ee8eb13564..ded77b394066 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -518,8 +518,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private final SparseBooleanArray mRestrictBackgroundAllowlistRevokedUids =
new SparseBooleanArray();
+ final Object mMeteredIfacesLock = new Object();
/** Set of ifaces that are metered. */
- @GuardedBy("mNetworkPoliciesSecondLock")
+ @GuardedBy("mMeteredIfacesLock")
private ArraySet<String> mMeteredIfaces = new ArraySet<>();
/** Set of over-limit templates that have been notified. */
@GuardedBy("mNetworkPoliciesSecondLock")
@@ -1972,13 +1973,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
// Remove quota from any interfaces that are no longer metered.
- for (int i = mMeteredIfaces.size() - 1; i >= 0; i--) {
- final String iface = mMeteredIfaces.valueAt(i);
- if (!newMeteredIfaces.contains(iface)) {
- removeInterfaceQuotaAsync(iface);
+ synchronized (mMeteredIfacesLock) {
+ for (int i = mMeteredIfaces.size() - 1; i >= 0; i--) {
+ final String iface = mMeteredIfaces.valueAt(i);
+ if (!newMeteredIfaces.contains(iface)) {
+ removeInterfaceQuotaAsync(iface);
+ }
}
+ mMeteredIfaces = newMeteredIfaces;
}
- mMeteredIfaces = newMeteredIfaces;
final ContentResolver cr = mContext.getContentResolver();
final boolean quotaEnabled = Settings.Global.getInt(cr,
@@ -2030,7 +2033,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mSubscriptionOpportunisticQuota.put(subId, quotaBytes);
}
- final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
+ final String[] meteredIfaces;
+ synchronized (mMeteredIfacesLock) {
+ meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
+ }
mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget();
mHandler.obtainMessage(MSG_ADVISE_PERSIST_THRESHOLD, lowestRule).sendToTarget();
@@ -3436,7 +3442,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
fout.print("Restrict background: "); fout.println(mRestrictBackground);
fout.print("Restrict power: "); fout.println(mRestrictPower);
fout.print("Device idle: "); fout.println(mDeviceIdleMode);
- fout.print("Metered ifaces: "); fout.println(mMeteredIfaces);
+ synchronized (mMeteredIfacesLock) {
+ fout.print("Metered ifaces: ");
+ fout.println(mMeteredIfaces);
+ }
fout.println();
fout.print("mRestrictBackgroundLowPowerMode: " + mRestrictBackgroundLowPowerMode);
@@ -4632,7 +4641,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
case MSG_LIMIT_REACHED: {
final String iface = (String) msg.obj;
- synchronized (mNetworkPoliciesSecondLock) {
+ synchronized (mMeteredIfacesLock) {
// fast return if not needed.
if (!mMeteredIfaces.contains(iface)) {
return true;
@@ -5274,7 +5283,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
isBackgroundRestricted = mRestrictBackground;
}
final boolean isNetworkMetered;
- synchronized (mNetworkPoliciesSecondLock) {
+ synchronized (mMeteredIfacesLock) {
isNetworkMetered = mMeteredIfaces.contains(ifname);
}
final boolean ret = isUidNetworkingBlockedInternal(uid, uidRules, isNetworkMetered,
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 3d7c978ca625..f168ac70dda8 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -560,9 +560,9 @@ public class AppsFilter {
final boolean newIsForceQueryable =
mForceQueryable.contains(newPkgSetting.appId)
/* shared user that is already force queryable */
- || newPkg.isForceQueryable()
- || newPkgSetting.forceQueryableOverride
+ || newPkgSetting.forceQueryableOverride /* adb override */
|| (newPkgSetting.isSystem() && (mSystemAppsQueryable
+ || newPkg.isForceQueryable()
|| ArrayUtils.contains(mForceQueryableByDevicePackageNames,
newPkg.getPackageName())));
if (newIsForceQueryable
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index e44c8ab3f7f3..6ecaab6692a2 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -407,6 +407,10 @@ public class UserManagerService extends IUserManager.Stub {
@GuardedBy("mUsersLock")
private int[] mUserIds;
+
+ @GuardedBy("mUsersLock")
+ private int[] mUserIdsIncludingPreCreated;
+
@GuardedBy("mPackagesLock")
private int mNextSerialNumber;
private int mUserVersion = 0;
@@ -2496,16 +2500,35 @@ public class UserManagerService extends IUserManager.Stub {
}
/**
- * Returns an array of user ids. This array is cached here for quick access, so do not modify or
- * cache it elsewhere.
+ * Returns an array of user ids.
+ *
+ * <p>This array is cached here for quick access, so do not modify or cache it elsewhere.
+ *
* @return the array of user ids.
*/
- public int[] getUserIds() {
+ public @NonNull int[] getUserIds() {
synchronized (mUsersLock) {
return mUserIds;
}
}
+ /**
+ * Returns an array of user ids, including pre-created users.
+ *
+ * <p>This method should only used for the specific cases that need to handle pre-created users;
+ * most callers should call {@link #getUserIds()} instead.
+ *
+ * <p>This array is cached here for quick access, so do not modify or
+ * cache it elsewhere.
+ *
+ * @return the array of user ids.
+ */
+ public @NonNull int[] getUserIdsIncludingPreCreated() {
+ synchronized (mUsersLock) {
+ return mUserIdsIncludingPreCreated;
+ }
+ }
+
@GuardedBy({"mRestrictionsLock", "mPackagesLock"})
private void readUserListLP() {
if (!mUserListFile.exists()) {
@@ -4361,23 +4384,43 @@ public class UserManagerService extends IUserManager.Stub {
*/
private void updateUserIds() {
int num = 0;
+ int numIncludingPreCreated = 0;
synchronized (mUsersLock) {
final int userSize = mUsers.size();
for (int i = 0; i < userSize; i++) {
- UserInfo userInfo = mUsers.valueAt(i).info;
- if (!userInfo.partial && !userInfo.preCreated) {
- num++;
+ final UserInfo userInfo = mUsers.valueAt(i).info;
+ if (!userInfo.partial) {
+ numIncludingPreCreated++;
+ if (!userInfo.preCreated) {
+ num++;
+ }
}
}
+ if (DBG) {
+ Slog.d(LOG_TAG, "updateUserIds(): numberUsers= " + num
+ + " includingPreCreated=" + numIncludingPreCreated);
+ }
final int[] newUsers = new int[num];
+ final int[] newUsersIncludingPreCreated = new int[numIncludingPreCreated];
+
int n = 0;
+ int nIncludingPreCreated = 0;
for (int i = 0; i < userSize; i++) {
- UserInfo userInfo = mUsers.valueAt(i).info;
- if (!userInfo.partial && !userInfo.preCreated) {
- newUsers[n++] = mUsers.keyAt(i);
+ final UserInfo userInfo = mUsers.valueAt(i).info;
+ if (!userInfo.partial) {
+ final int userId = mUsers.keyAt(i);
+ newUsersIncludingPreCreated[nIncludingPreCreated++] = userId;
+ if (!userInfo.preCreated) {
+ newUsers[n++] = userId;
+ }
}
}
mUserIds = newUsers;
+ mUserIdsIncludingPreCreated = newUsersIncludingPreCreated;
+ if (DBG) {
+ Slog.d(LOG_TAG, "updateUserIds(): userIds= " + Arrays.toString(mUserIds)
+ + " includingPreCreated=" + Arrays.toString(mUserIdsIncludingPreCreated));
+ }
}
}
@@ -4841,6 +4884,8 @@ public class UserManagerService extends IUserManager.Stub {
synchronized (mUsersLock) {
pw.print(" Cached user IDs: ");
pw.println(Arrays.toString(mUserIds));
+ pw.print(" Cached user IDs (including pre-created): ");
+ pw.println(Arrays.toString(mUserIdsIncludingPreCreated));
}
} // synchronized (mPackagesLock)
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index f5dd918a18f3..ffdcc227b7f1 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -83,7 +83,6 @@ import android.content.pm.PackageParser;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
-import android.content.pm.UserInfo;
import android.content.pm.parsing.component.ParsedPermission;
import android.content.pm.parsing.component.ParsedPermissionGroup;
import android.content.pm.permission.SplitPermissionInfoParcelable;
@@ -121,7 +120,6 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import android.util.TimingsTraceLog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -3146,17 +3144,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
* @return user ids for created users and pre-created users
*/
private int[] getAllUserIds() {
- final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
- t.traceBegin("getAllUserIds");
- List<UserInfo> users = UserManagerService.getInstance().getUsers(
- /*excludePartial=*/ true, /*excludeDying=*/ true, /*excludePreCreated=*/ false);
- int size = users.size();
- final int[] userIds = new int[size];
- for (int i = 0; i < size; i++) {
- userIds[i] = users.get(i).id;
- }
- t.traceEnd();
- return userIds;
+ return UserManagerService.getInstance().getUserIdsIncludingPreCreated();
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index aea0a58c9acb..9f68d627622c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1586,7 +1586,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
hasBeenLaunched = false;
mStackSupervisor = supervisor;
- info.taskAffinity = getTaskAffinityWithUid(info.taskAffinity, info.applicationInfo.uid);
+ info.taskAffinity = computeTaskAffinity(info.taskAffinity, info.applicationInfo.uid,
+ launchMode);
taskAffinity = info.taskAffinity;
final String uid = Integer.toString(info.applicationInfo.uid);
if (info.windowLayout != null && info.windowLayout.windowLayoutAffinity != null
@@ -1647,17 +1648,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
/**
- * Generate the task affinity with uid. For b/35954083, Limit task affinity to uid to avoid
- * issues associated with sharing affinity across uids.
+ * Generate the task affinity with uid and activity launch mode. For b/35954083, Limit task
+ * affinity to uid to avoid issues associated with sharing affinity across uids.
*
* @param affinity The affinity of the activity.
* @param uid The user-ID that has been assigned to this application.
- * @return The task affinity with uid.
+ * @param launchMode The activity launch mode
+ * @return The task affinity
*/
- static String getTaskAffinityWithUid(String affinity, int uid) {
+ static String computeTaskAffinity(String affinity, int uid, int launchMode) {
final String uidStr = Integer.toString(uid);
if (affinity != null && !affinity.startsWith(uidStr)) {
- affinity = uidStr + ":" + affinity;
+ affinity = uidStr + (launchMode == LAUNCH_SINGLE_INSTANCE ? "-si:" : ":") + affinity;
}
return affinity;
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 1c147c259f07..abfbf2eb8b67 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -38,11 +38,6 @@ import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.InsetsState.ITYPE_TOP_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_TOP_GESTURES;
import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
-import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
-import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
-import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
@@ -57,15 +52,12 @@ import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCRE
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
-import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
@@ -78,27 +70,21 @@ import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
-import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManagerGlobal.ADD_OKAY;
import static android.view.WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED;
@@ -171,7 +157,6 @@ import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.Surface;
import android.view.View;
-import android.view.ViewRootImpl;
import android.view.WindowInsets.Side;
import android.view.WindowInsets.Side.InsetsSide;
import android.view.WindowInsets.Type;
@@ -1440,8 +1425,7 @@ public class DisplayPolicy {
DisplayCutout.ParcelableWrapper outDisplayCutout) {
final int fl = PolicyControl.getWindowFlags(null, attrs);
final int pfl = attrs.privateFlags;
- final int requestedSysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
- final int sysUiVis = requestedSysUiVis | getImpliedSysUiFlagsForLayout(attrs);
+ final int sysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0;
final boolean layoutInScreenAndInsetDecor = layoutInScreen
@@ -1461,7 +1445,7 @@ public class DisplayPolicy {
: mDisplayContent.mDisplayFrames;
if (layoutInScreenAndInsetDecor && !screenDecor) {
- if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
+ if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
|| (attrs.getFitInsetsTypes() & Type.navigationBars()) == 0) {
outFrame.set(displayFrames.mUnrestricted);
} else {
@@ -1492,7 +1476,6 @@ public class DisplayPolicy {
InsetUtils.insetsBetweenFrames(outFrame, sf, outStableInsets);
outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame)
.getDisplayCutout());
- return mForceShowSystemBars;
} else {
if (layoutInScreen) {
outFrame.set(displayFrames.mUnrestricted);
@@ -1506,22 +1489,8 @@ public class DisplayPolicy {
outContentInsets.setEmpty();
outStableInsets.setEmpty();
outDisplayCutout.set(DisplayCutout.NO_CUTOUT);
- return mForceShowSystemBars;
}
- }
-
- // TODO(b/118118435): remove after migration
- private static int getImpliedSysUiFlagsForLayout(LayoutParams attrs) {
- int impliedFlags = 0;
- final boolean forceWindowDrawsBarBackgrounds =
- (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
- && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT;
- if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
- || forceWindowDrawsBarBackgrounds) {
- impliedFlags |= SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
- impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
- }
- return impliedFlags;
+ return mForceShowSystemBars;
}
private final Runnable mClearHideNavigationFlag = new Runnable() {
@@ -1668,11 +1637,8 @@ public class DisplayPolicy {
final int behavior = mLastBehavior;
final InsetsSourceProvider provider =
mDisplayContent.getInsetsStateController().peekSourceProvider(ITYPE_NAVIGATION_BAR);
- boolean navVisible = ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL
- ? (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
- : provider != null
- ? provider.isClientVisible()
- : InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR);
+ boolean navVisible = provider != null ? provider.isClientVisible()
+ : InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR);
boolean navTranslucent = (sysui
& (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0;
boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0
@@ -2057,80 +2023,6 @@ public class DisplayPolicy {
return mNavigationBarController.checkHiddenLw();
}
- private void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
- boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf,
- DisplayFrames displayFrames) {
- if (!win.isInputMethodTarget() && attached.isInputMethodTarget()) {
- // Here's a special case: if the child window is not the 'dock window'
- // or input method target, and the window it is attached to is below
- // the dock window, then the frames we computed for the window it is
- // attached to can not be used because the dock is effectively part
- // of the underlying window and the attached window is floating on top
- // of the whole thing. So, we ignore the attached window and explicitly
- // compute the frames that would be appropriate without the dock.
- vf.set(displayFrames.mDock);
- cf.set(displayFrames.mDock);
- df.set(displayFrames.mDock);
- } else {
-
- // In case we forced the window to draw behind the navigation bar, restrict df to
- // DF.Restricted to simulate old compat behavior.
- Rect parentDisplayFrame = attached.getDisplayFrame();
- final WindowManager.LayoutParams attachedAttrs = attached.mAttrs;
- if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
- && (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
- && (attachedAttrs.systemUiVisibility
- & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0) {
- parentDisplayFrame = new Rect(parentDisplayFrame);
- parentDisplayFrame.intersect(displayFrames.mRestricted);
- }
-
- // The effective display frame of the attached window depends on whether it is taking
- // care of insetting its content. If not, we need to use the parent's content frame so
- // that the entire window is positioned within that content. Otherwise we can use the
- // parent display frame and let the attached window take care of positioning its content
- // appropriately.
- if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
- // Set the content frame of the attached window to the parent's decor frame
- // (same as content frame when IME isn't present) if specifically requested by
- // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
- // Otherwise, use the overscan frame.
- cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
- ? attached.getContentFrame() : parentDisplayFrame);
- } else {
- // If the window is resizing, then we want to base the content frame on our attached
- // content frame to resize...however, things can be tricky if the attached window is
- // NOT in resize mode, in which case its content frame will be larger.
- // Ungh. So to deal with that, make sure the content frame we end up using is not
- // covering the IM dock.
- cf.set(attached.getContentFrame());
- if (attached.isVoiceInteraction()) {
- cf.intersectUnchecked(displayFrames.mVoiceContent);
- } else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) {
- cf.intersectUnchecked(displayFrames.mContent);
- }
- }
- df.set(insetDecors ? parentDisplayFrame : cf);
- vf.set(attached.getVisibleFrame());
- }
- // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
- // positioned relative to its parent or the entire screen.
- pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrame() : df);
- }
-
- private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) {
- if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) == 0) {
- return;
- }
- // If app is requesting a stable layout, don't let the content insets go below the stable
- // values.
- if ((fl & FLAG_FULLSCREEN) != 0) {
- r.intersectUnchecked(displayFrames.mStableFullscreen);
- } else {
- r.intersectUnchecked(displayFrames.mStable);
- }
- }
-
private boolean canReceiveInput(WindowState win) {
boolean notFocusable =
(win.getAttrs().flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0;
@@ -2163,10 +2055,7 @@ public class DisplayPolicy {
final int type = attrs.type;
final int fl = PolicyControl.getWindowFlags(win, attrs);
- final int pfl = attrs.privateFlags;
final int sim = attrs.softInputMode;
- final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
- final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
displayFrames = win.getDisplayFrames(displayFrames);
final WindowFrames windowFrames = win.getWindowFrames();
@@ -2191,351 +2080,53 @@ public class DisplayPolicy {
sf.set(displayFrames.mStable);
- if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
- final @InsetsType int typesToFit = attrs.getFitInsetsTypes();
- final @InsetsSide int sidesToFit = attrs.getFitInsetsSides();
- final ArraySet<Integer> types = InsetsState.toInternalType(typesToFit);
- getRotatedWindowBounds(displayFrames, win, sTmpRect);
- final Rect dfu = sTmpRect;
- Insets insets = Insets.of(0, 0, 0, 0);
- for (int i = types.size() - 1; i >= 0; i--) {
- final InsetsSource source = mDisplayContent.getInsetsPolicy()
- .getInsetsForDispatch(win).peekSource(types.valueAt(i));
- if (source == null) {
- continue;
- }
- insets = Insets.max(insets, source.calculateInsets(
- dfu, attrs.isFitInsetsIgnoringVisibility()));
- }
- final int left = (sidesToFit & Side.LEFT) != 0 ? insets.left : 0;
- final int top = (sidesToFit & Side.TOP) != 0 ? insets.top : 0;
- final int right = (sidesToFit & Side.RIGHT) != 0 ? insets.right : 0;
- final int bottom = (sidesToFit & Side.BOTTOM) != 0 ? insets.bottom : 0;
- df.set(dfu.left + left, dfu.top + top, dfu.right - right, dfu.bottom - bottom);
- if (attached == null) {
- pf.set(df);
- vf.set(adjust != SOFT_INPUT_ADJUST_NOTHING
- ? displayFrames.mCurrent : displayFrames.mDock);
- } else {
- pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrame() : df);
- vf.set(attached.getVisibleFrame());
- }
- cf.set(adjust != SOFT_INPUT_ADJUST_RESIZE
- ? displayFrames.mDock : displayFrames.mContent);
- dcf.set(displayFrames.mSystem);
- } else if (type == TYPE_INPUT_METHOD) {
- vf.set(displayFrames.mDock);
- cf.set(displayFrames.mDock);
- df.set(displayFrames.mDock);
- pf.set(displayFrames.mDock);
- // IM dock windows layout below the nav bar...
- pf.bottom = df.bottom = displayFrames.mUnrestricted.bottom;
- // ...with content insets above the nav bar
- cf.bottom = vf.bottom = displayFrames.mStable.bottom;
- if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
- // The status bar forces the navigation bar while it's visible. Make sure the IME
- // avoids the navigation bar in that case.
- if (mNavigationBarPosition == NAV_BAR_RIGHT) {
- pf.right = df.right = cf.right = vf.right =
- displayFrames.mStable.right;
- } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
- pf.left = df.left = cf.left = vf.left = displayFrames.mStable.left;
- }
- }
-
- // In case the navigation bar is on the bottom, we use the frame height instead of the
- // regular height for the insets we send to the IME as we need some space to show
- // additional buttons in SystemUI when the IME is up.
- if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
- final int rotation = displayFrames.mRotation;
- final int uimode = mService.mPolicy.getUiMode();
- final int navHeightOffset = getNavigationBarFrameHeight(rotation, uimode)
- - getNavigationBarHeight(rotation, uimode);
- if (navHeightOffset > 0) {
- cf.bottom -= navHeightOffset;
- sf.bottom -= navHeightOffset;
- vf.bottom -= navHeightOffset;
- dcf.bottom -= navHeightOffset;
- }
- }
-
- // IM dock windows always go to the bottom of the screen.
- attrs.gravity = Gravity.BOTTOM;
- } else if (type == TYPE_VOICE_INTERACTION) {
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
- cf.set(displayFrames.mDock);
- } else {
- cf.set(displayFrames.mContent);
- }
- if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
- vf.set(displayFrames.mCurrent);
- } else {
- vf.set(cf);
- }
- } else if (type == TYPE_WALLPAPER) {
- layoutWallpaper(displayFrames, pf, df, cf);
- } else if (win == mStatusBar || type == TYPE_NOTIFICATION_SHADE) {
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- cf.set(displayFrames.mStable);
- vf.set(displayFrames.mStable);
-
- if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
- // cf.bottom should not be below the stable bottom, or the content might be obscured
- // by the navigation bar.
- if (cf.bottom > displayFrames.mContent.bottom) {
- cf.bottom = displayFrames.mContent.bottom;
- }
- } else {
- if (cf.bottom > displayFrames.mDock.bottom) {
- cf.bottom = displayFrames.mDock.bottom;
- }
- if (vf.bottom > displayFrames.mContent.bottom) {
- vf.bottom = displayFrames.mContent.bottom;
- }
+ final @InsetsType int typesToFit = attrs.getFitInsetsTypes();
+ final @InsetsSide int sidesToFit = attrs.getFitInsetsSides();
+ final ArraySet<Integer> types = InsetsState.toInternalType(typesToFit);
+ getRotatedWindowBounds(displayFrames, win, sTmpRect);
+ final Rect dfu = sTmpRect;
+ Insets insets = Insets.of(0, 0, 0, 0);
+ for (int i = types.size() - 1; i >= 0; i--) {
+ final InsetsSource source = mDisplayContent.getInsetsPolicy()
+ .getInsetsForDispatch(win).peekSource(types.valueAt(i));
+ if (source == null) {
+ continue;
}
+ insets = Insets.max(insets, source.calculateInsets(
+ dfu, attrs.isFitInsetsIgnoringVisibility()));
+ }
+ final int left = (sidesToFit & Side.LEFT) != 0 ? insets.left : 0;
+ final int top = (sidesToFit & Side.TOP) != 0 ? insets.top : 0;
+ final int right = (sidesToFit & Side.RIGHT) != 0 ? insets.right : 0;
+ final int bottom = (sidesToFit & Side.BOTTOM) != 0 ? insets.bottom : 0;
+ df.set(dfu.left + left, dfu.top + top, dfu.right - right, dfu.bottom - bottom);
+ if (attached == null) {
+ pf.set(df);
+ vf.set(adjust != SOFT_INPUT_ADJUST_NOTHING
+ ? displayFrames.mCurrent : displayFrames.mDock);
} else {
- dcf.set(displayFrames.mSystem);
- final boolean isAppWindow =
- type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW;
- final boolean topAtRest =
- win == mTopFullscreenOpaqueWindowState && !win.isAnimatingLw();
- if (isAppWindow && !topAtRest) {
- if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
- && (fl & FLAG_FULLSCREEN) == 0
- && (fl & FLAG_TRANSLUCENT_STATUS) == 0
- && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
- && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
- // Ensure policy decor includes status bar
- dcf.top = displayFrames.mStable.top;
- }
- if ((fl & FLAG_TRANSLUCENT_NAVIGATION) == 0
- && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
- && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
- && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
- // Ensure policy decor includes navigation bar
- dcf.bottom = displayFrames.mStable.bottom;
- dcf.right = displayFrames.mStable.right;
- }
- }
-
- if (layoutInScreen && layoutInsetDecor) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
- + "): IN_SCREEN, INSET_DECOR");
- // This is the case for a normal activity window: we want it to cover all of the
- // screen space, and it can take care of moving its contents to account for screen
- // decorations that intrude into that space.
- if (attached != null) {
- // If this window is attached to another, our display
- // frame is the same as the one we are attached to.
- setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, cf, vf,
- displayFrames);
- } else {
- if (type == TYPE_STATUS_BAR_ADDITIONAL || type == TYPE_STATUS_BAR_SUB_PANEL) {
- // Status bar panels are the only windows who can go on top of the status
- // bar. They are protected by the STATUS_BAR_SERVICE permission, so they
- // have the same privileges as the status bar itself.
- //
- // However, they should still dodge the navigation bar if it exists.
-
- pf.left = df.left = hasNavBar
- ? displayFrames.mDock.left : displayFrames.mUnrestricted.left;
- pf.top = df.top = displayFrames.mUnrestricted.top;
- pf.right = df.right = hasNavBar
- ? displayFrames.mRestricted.right
- : displayFrames.mUnrestricted.right;
- pf.bottom = df.bottom = hasNavBar
- ? displayFrames.mRestricted.bottom
- : displayFrames.mUnrestricted.bottom;
-
- if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf);
- } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
- && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
- || type == TYPE_VOLUME_OVERLAY
- || type == TYPE_KEYGUARD_DIALOG)) {
- // Asking for layout as if the nav bar is hidden, lets the application
- // extend into the unrestricted overscan screen area. We only do this for
- // application windows and certain system windows to ensure no window that
- // can be above the nav bar can do this.
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- } else {
- df.set(displayFrames.mRestricted);
- pf.set(displayFrames.mRestricted);
- }
-
- if ((fl & FLAG_FULLSCREEN) == 0) {
- if (win.isVoiceInteraction()) {
- cf.set(displayFrames.mVoiceContent);
- } else {
- // IME Insets are handled on the client for ADJUST_RESIZE in the new
- // insets world
- if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
- || adjust != SOFT_INPUT_ADJUST_RESIZE) {
- cf.set(displayFrames.mDock);
- } else {
- cf.set(displayFrames.mContent);
- }
- }
- } else {
- // Full screen windows are always given a layout that is as if the status
- // bar and other transient decors are gone. This is to avoid bad states when
- // moving from a window that is not hiding the status bar to one that is.
- cf.set(displayFrames.mRestricted);
- }
- applyStableConstraints(sysUiFl, fl, cf, displayFrames);
- if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE
- && adjust != SOFT_INPUT_ADJUST_NOTHING) {
- vf.set(displayFrames.mCurrent);
- } else {
- vf.set(cf);
- }
- }
- } else if (layoutInScreen || (sysUiFl
- & (SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
- + "): IN_SCREEN");
- // A window that has requested to fill the entire screen just
- // gets everything, period.
- if (type == TYPE_STATUS_BAR_ADDITIONAL || type == TYPE_STATUS_BAR_SUB_PANEL) {
- cf.set(displayFrames.mUnrestricted);
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- if (hasNavBar) {
- pf.left = df.left = cf.left = displayFrames.mDock.left;
- pf.right = df.right = cf.right = displayFrames.mRestricted.right;
- pf.bottom = df.bottom = cf.bottom =
- displayFrames.mRestricted.bottom;
- }
- if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf);
- } else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
- // The navigation bar has Real Ultimate Power.
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf);
- } else if ((type == TYPE_SECURE_SYSTEM_OVERLAY || type == TYPE_SCREENSHOT)
- && ((fl & FLAG_FULLSCREEN) != 0)) {
- // Fullscreen secure system overlays get what they ask for. Screenshot region
- // selection overlay should also expand to full screen.
- cf.set(displayFrames.mUnrestricted);
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- } else if (type == TYPE_BOOT_PROGRESS) {
- // Boot progress screen always covers entire display.
- cf.set(displayFrames.mUnrestricted);
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
- && (type == TYPE_NOTIFICATION_SHADE
- || type == TYPE_TOAST
- || type == TYPE_DOCK_DIVIDER
- || type == TYPE_VOICE_INTERACTION_STARTING
- || (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW))) {
- // Asking for layout as if the nav bar is hidden, lets the
- // application extend into the unrestricted screen area. We
- // only do this for application windows (or toasts) to ensure no window that
- // can be above the nav bar can do this.
- // XXX This assumes that an app asking for this will also
- // ask for layout in only content. We can't currently figure out
- // what the screen would be if only laying out to hide the nav bar.
- cf.set(displayFrames.mUnrestricted);
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
- df.set(displayFrames.mRestricted);
- pf.set(displayFrames.mRestricted);
-
- // IME Insets are handled on the client for ADJUST_RESIZE in the new insets
- // world
- if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
- || adjust != SOFT_INPUT_ADJUST_RESIZE) {
- cf.set(displayFrames.mDock);
- } else {
- cf.set(displayFrames.mContent);
- }
- } else {
- cf.set(displayFrames.mRestricted);
- df.set(displayFrames.mRestricted);
- pf.set(displayFrames.mRestricted);
- }
-
- applyStableConstraints(sysUiFl, fl, cf, displayFrames);
-
- if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE
- && adjust != SOFT_INPUT_ADJUST_NOTHING) {
- vf.set(displayFrames.mCurrent);
- } else {
- vf.set(cf);
- }
- } else if (attached != null) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
- + "): attached to " + attached);
- // A child window should be placed inside of the same visible
- // frame that its parent had.
- setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf,
- displayFrames);
- } else {
- if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
- + "): normal window");
- // Otherwise, a normal window must be placed inside the content
- // of all screen decorations.
- if (type == TYPE_STATUS_BAR_ADDITIONAL) {
- // Status bar panels can go on
- // top of the status bar. They are protected by the STATUS_BAR_SERVICE
- // permission, so they have the same privileges as the status bar itself.
- cf.set(displayFrames.mRestricted);
- df.set(displayFrames.mRestricted);
- pf.set(displayFrames.mRestricted);
- } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
- // These dialogs are stable to interim decor changes.
- cf.set(displayFrames.mStable);
- df.set(displayFrames.mStable);
- pf.set(displayFrames.mStable);
- } else {
- pf.set(displayFrames.mContent);
- if (win.isVoiceInteraction()) {
- cf.set(displayFrames.mVoiceContent);
- df.set(displayFrames.mVoiceContent);
- } else if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
- cf.set(displayFrames.mDock);
- df.set(displayFrames.mDock);
- } else {
- cf.set(displayFrames.mContent);
- df.set(displayFrames.mContent);
- }
- if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE
- && adjust != SOFT_INPUT_ADJUST_NOTHING) {
- vf.set(displayFrames.mCurrent);
- } else {
- vf.set(cf);
- }
- }
- }
+ pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrame() : df);
+ vf.set(attached.getVisibleFrame());
}
+ cf.set(adjust != SOFT_INPUT_ADJUST_RESIZE
+ ? displayFrames.mDock : displayFrames.mContent);
+ dcf.set(displayFrames.mSystem);
final int cutoutMode = attrs.layoutInDisplayCutoutMode;
- final boolean attachedInParent = attached != null && !layoutInScreen;
- final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
- || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0
- || (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL
- && !win.getRequestedInsetsState().getSourceOrDefaultVisibility(
- ITYPE_STATUS_BAR));
- final boolean requestedHideNavigation =
- (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
- || (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL
- && !win.getRequestedInsetsState().getSourceOrDefaultVisibility(
- ITYPE_NAVIGATION_BAR));
-
- // TYPE_BASE_APPLICATION windows are never considered floating here because they don't get
- // cropped / shifted to the displayFrame in WindowState.
- final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
- && type != TYPE_BASE_APPLICATION;
// Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
// the cutout safe zone.
if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
+ final boolean attachedInParent = attached != null && !layoutInScreen;
+ final InsetsState requestedInsetsState = win.getRequestedInsetsState();
+ final boolean requestedFullscreen =
+ !requestedInsetsState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR);
+ final boolean requestedHideNavigation =
+ !requestedInsetsState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR);
+
+ // TYPE_BASE_APPLICATION windows are never considered floating here because they don't
+ // get cropped / shifted to the displayFrame in WindowState.
+ final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
+ && type != TYPE_BASE_APPLICATION;
final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect;
displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
if (cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) {
@@ -2631,13 +2222,6 @@ public class DisplayPolicy {
}
}
- private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect cf) {
- // The wallpaper has Real Ultimate Power
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- cf.set(displayFrames.mUnrestricted);
- }
-
private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) {
final int rotation = displayFrames.mRotation;
final int navBarPosition = navigationBarPosition(displayFrames.mDisplayWidth,
@@ -3343,54 +2927,37 @@ public class DisplayPolicy {
// Swipe-up for navigation bar is disabled during setup
return;
}
- if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
- final InsetsSourceProvider provider = swipeTarget.getControllableInsetProvider();
- final InsetsControlTarget controlTarget = provider != null
- ? provider.getControlTarget() : null;
+ final InsetsSourceProvider provider = swipeTarget.getControllableInsetProvider();
+ final InsetsControlTarget controlTarget = provider != null
+ ? provider.getControlTarget() : null;
- if (controlTarget == null || controlTarget == getNotificationShade()) {
- // No transient mode on lockscreen (in notification shade window).
- return;
- }
+ if (controlTarget == null || controlTarget == getNotificationShade()) {
+ // No transient mode on lockscreen (in notification shade window).
+ return;
+ }
- final InsetsState requestedState = controlTarget.getRequestedInsetsState();
- final @InsetsType int restorePositionTypes =
- (requestedState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)
- ? Type.navigationBars() : 0)
- | (requestedState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR)
- ? Type.statusBars() : 0);
-
- if (swipeTarget == mNavigationBar
- && (restorePositionTypes & Type.navigationBars()) != 0) {
- // Don't show status bar when swiping on already visible navigation bar.
- // But restore the position of navigation bar if it has been moved by the control
- // target.
- controlTarget.showInsets(Type.navigationBars(), false);
- return;
- }
+ final InsetsState requestedState = controlTarget.getRequestedInsetsState();
+ final @InsetsType int restorePositionTypes = (requestedState.getSourceOrDefaultVisibility(
+ ITYPE_NAVIGATION_BAR) ? Type.navigationBars() : 0) | (
+ requestedState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR) ? Type.statusBars()
+ : 0);
- if (controlTarget.canShowTransient()) {
- // Show transient bars if they are hidden; restore position if they are visible.
- mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_SWIPE);
- controlTarget.showInsets(restorePositionTypes, false);
- } else {
- // Restore visibilities and positions of system bars.
- controlTarget.showInsets(Type.statusBars() | Type.navigationBars(), false);
- }
+ if (swipeTarget == mNavigationBar
+ && (restorePositionTypes & Type.navigationBars()) != 0) {
+ // Don't show status bar when swiping on already visible navigation bar.
+ // But restore the position of navigation bar if it has been moved by the control
+ // target.
+ controlTarget.showInsets(Type.navigationBars(), false);
+ return;
+ }
+
+ if (controlTarget.canShowTransient()) {
+ // Show transient bars if they are hidden; restore position if they are visible.
+ mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_SWIPE);
+ controlTarget.showInsets(restorePositionTypes, false);
} else {
- boolean sb = mStatusBarController.checkShowTransientBarLw();
- boolean nb = mNavigationBarController.checkShowTransientBarLw()
- && !isNavBarEmpty(mLastSystemUiFlags);
- if (sb || nb) {
- // Don't show status bar when swiping on already visible navigation bar
- if (!nb && swipeTarget == mNavigationBar) {
- if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
- return;
- }
- if (sb) mStatusBarController.showTransient();
- if (nb) mNavigationBarController.showTransient();
- updateSystemUiVisibilityLw();
- }
+ // Restore visibilities and positions of system bars.
+ controlTarget.showInsets(Type.statusBars() | Type.navigationBars(), false);
}
mImmersiveModeConfirmation.confirmCurrentPrompt();
}
@@ -3479,11 +3046,10 @@ public class DisplayPolicy {
navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow;
final int opaqueAppearance = InsetsFlags.getAppearance(visibility)
& (APPEARANCE_OPAQUE_STATUS_BARS | APPEARANCE_OPAQUE_NAVIGATION_BARS);
- final int appearance = ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL
- ? updateLightNavigationBarAppearanceLw(win.mAttrs.insetsFlags.appearance,
- mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
- mDisplayContent.mInputMethodWindow, navColorWin) | opaqueAppearance
- : InsetsFlags.getAppearance(visibility);
+ final int appearance = updateLightNavigationBarAppearanceLw(
+ win.mAttrs.insetsFlags.appearance, mTopFullscreenOpaqueWindowState,
+ mTopFullscreenOpaqueOrDimmingWindowState,
+ mDisplayContent.mInputMethodWindow, navColorWin) | opaqueAppearance;
final int diff = visibility ^ mLastSystemUiFlags;
final InsetsPolicy insetsPolicy = getInsetsPolicy();
final boolean isFullscreen = (visibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
@@ -3805,9 +3371,8 @@ public class DisplayPolicy {
vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
// update navigation bar
- boolean newInsetsMode = ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL;
- boolean oldImmersiveMode = newInsetsMode ? mLastImmersiveMode : isImmersiveMode(oldVis);
- boolean newImmersiveMode = newInsetsMode ? isImmersiveMode(win) : isImmersiveMode(vis);
+ boolean oldImmersiveMode = mLastImmersiveMode;
+ boolean newImmersiveMode = isImmersiveMode(win);
if (oldImmersiveMode != newImmersiveMode) {
mLastImmersiveMode = newImmersiveMode;
final String pkg = win.getOwningPackage();
@@ -3911,15 +3476,6 @@ public class DisplayPolicy {
}
}
- // TODO(b/118118435): Remove this after migration
- private boolean isImmersiveMode(int vis) {
- final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
- return getNavigationBar() != null
- && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
- && (vis & flags) != 0
- && canHideNavigationBar();
- }
-
private boolean isImmersiveMode(WindowState win) {
if (win == null) {
return false;
@@ -4110,9 +3666,7 @@ public class DisplayPolicy {
mPointerLocationView = new PointerLocationView(mContext);
mPointerLocationView.setPrintCoords(false);
- final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- WindowManager.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.MATCH_PARENT);
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
lp.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 5606eb676b1d..70fd860f21f2 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -6637,7 +6637,8 @@ class Task extends WindowContainer<WindowContainer> {
// Basic case: for simple app-centric recents, we need to recreate
// the task if the affinity has changed.
- final String affinity = ActivityRecord.getTaskAffinityWithUid(destAffinity, srec.getUid());
+ final String affinity = ActivityRecord.computeTaskAffinity(destAffinity, srec.getUid(),
+ srec.launchMode);
if (srec == null || srec.getTask().affinity == null
|| !srec.getTask().affinity.equals(affinity)) {
return true;
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 9751c46f93c9..5dd6cd7b42e9 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -233,7 +233,8 @@ public:
virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
virtual std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId);
virtual void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices);
- virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const InputDeviceIdentifier& identifier);
+ virtual std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
+ const InputDeviceIdentifier& identifier);
virtual std::string getDeviceAlias(const InputDeviceIdentifier& identifier);
virtual TouchAffineTransformation getTouchAffineTransformation(JNIEnv *env,
jfloatArray matrixArr);
@@ -622,12 +623,12 @@ void NativeInputManager::notifyInputDevicesChanged(const std::vector<InputDevice
checkAndClearExceptionFromCallback(env, "notifyInputDevicesChanged");
}
-sp<KeyCharacterMap> NativeInputManager::getKeyboardLayoutOverlay(
+std::shared_ptr<KeyCharacterMap> NativeInputManager::getKeyboardLayoutOverlay(
const InputDeviceIdentifier& identifier) {
ATRACE_CALL();
JNIEnv* env = jniEnv();
- sp<KeyCharacterMap> result;
+ std::shared_ptr<KeyCharacterMap> result;
ScopedLocalRef<jstring> descriptor(env, env->NewStringUTF(identifier.descriptor.c_str()));
ScopedLocalRef<jobject> identifierObj(env, env->NewObject(gInputDeviceIdentifierInfo.clazz,
gInputDeviceIdentifierInfo.constructor, descriptor.get(),
@@ -642,8 +643,12 @@ sp<KeyCharacterMap> NativeInputManager::getKeyboardLayoutOverlay(
ScopedUtfChars filenameChars(env, filenameObj.get());
ScopedUtfChars contentsChars(env, contentsObj.get());
- KeyCharacterMap::loadContents(filenameChars.c_str(),
- contentsChars.c_str(), KeyCharacterMap::FORMAT_OVERLAY, &result);
+ base::Result<std::shared_ptr<KeyCharacterMap>> ret =
+ KeyCharacterMap::loadContents(filenameChars.c_str(), contentsChars.c_str(),
+ KeyCharacterMap::FORMAT_OVERLAY);
+ if (ret) {
+ result = *ret;
+ }
}
checkAndClearExceptionFromCallback(env, "getKeyboardLayoutOverlay");
return result;
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 777cbf410b9b..4e53aa218b71 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -928,7 +928,7 @@ Return<void> GnssCallback::gnssSetSystemInfoCb(const IGnssCallback_V2_0::GnssSys
* GnssPsdsCallback class implements the callback methods for the IGnssPsds
* interface.
*/
-class GnssPsdsCallback : public IGnssPsdsCallback {
+struct GnssPsdsCallback : public IGnssPsdsCallback {
Return<void> downloadRequestCb() override;
Return<void> downloadRequestCb_3_0(int32_t psdsType) override;
};
@@ -2743,19 +2743,26 @@ static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env
static jboolean android_location_GnssLocationProvider_supports_psds(
JNIEnv* /* env */, jobject /* obj */) {
- return (gnssXtraIface != nullptr) ? JNI_TRUE : JNI_FALSE;
+ return (gnssPsdsIface != nullptr || gnssXtraIface != nullptr) ? JNI_TRUE : JNI_FALSE;
}
static void android_location_GnssLocationProvider_inject_psds_data(JNIEnv* env, jobject /* obj */,
- jbyteArray data, jint length) {
- if (gnssXtraIface == nullptr) {
- ALOGE("%s: IGnssXtra interface not available.", __func__);
+ jbyteArray data, jint length,
+ jint psdsType) {
+ if (gnssPsdsIface == nullptr && gnssXtraIface == nullptr) {
+ ALOGE("%s: IGnssPsds or IGnssXtra interface not available.", __func__);
return;
}
jbyte* bytes = reinterpret_cast<jbyte *>(env->GetPrimitiveArrayCritical(data, 0));
- auto result = gnssXtraIface->injectXtraData(std::string((const char*)bytes, length));
- checkHidlReturn(result, "IGnssXtra injectXtraData() failed.");
+ if (gnssPsdsIface != nullptr) {
+ auto result = gnssPsdsIface->injectPsdsData_3_0(psdsType,
+ std::string((const char*)bytes, length));
+ checkHidlReturn(result, "IGnssPsds injectPsdsData() failed.");
+ } else if (gnssXtraIface != nullptr) {
+ auto result = gnssXtraIface->injectXtraData(std::string((const char*)bytes, length));
+ checkHidlReturn(result, "IGnssXtra injectXtraData() failed.");
+ }
env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
}
@@ -3685,7 +3692,7 @@ static const JNINativeMethod sLocationProviderMethods[] = {
reinterpret_cast<void*>(android_location_GnssLocationProvider_inject_location)},
{"native_supports_psds", "()Z",
reinterpret_cast<void*>(android_location_GnssLocationProvider_supports_psds)},
- {"native_inject_psds_data", "([BI)V",
+ {"native_inject_psds_data", "([BII)V",
reinterpret_cast<void*>(android_location_GnssLocationProvider_inject_psds_data)},
{"native_agps_set_id", "(ILjava/lang/String;)V",
reinterpret_cast<void*>(android_location_GnssLocationProvider_agps_set_id)},
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 3f324a279270..0c35797b38ea 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -697,7 +697,8 @@ public class HdmiCecLocalDevicePlaybackTest {
public void sendVolumeKeyEvent_toTv_activeSource() {
mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
mHdmiControlService.setSystemAudioActivated(false);
- mHdmiControlService.setActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
+ mHdmiControlService.setActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress,
+ "HdmiCecLocalDevicePlaybackTest");
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
@@ -716,7 +717,8 @@ public class HdmiCecLocalDevicePlaybackTest {
public void sendVolumeKeyEvent_toAudio_activeSource() {
mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
mHdmiControlService.setSystemAudioActivated(true);
- mHdmiControlService.setActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress);
+ mHdmiControlService.setActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress,
+ "HdmiCecLocalDevicePlaybackTest");
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
@@ -735,7 +737,7 @@ public class HdmiCecLocalDevicePlaybackTest {
public void sendVolumeKeyEvent_toTv_inactiveSource() {
mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
mHdmiControlService.setSystemAudioActivated(false);
- mHdmiControlService.setActiveSource(ADDR_TV, 0x0000);
+ mHdmiControlService.setActiveSource(ADDR_TV, 0x0000, "HdmiCecLocalDevicePlaybackTest");
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
@@ -754,7 +756,7 @@ public class HdmiCecLocalDevicePlaybackTest {
public void sendVolumeKeyEvent_toAudio_inactiveSource() {
mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
mHdmiControlService.setSystemAudioActivated(true);
- mHdmiControlService.setActiveSource(ADDR_TV, 0x0000);
+ mHdmiControlService.setActiveSource(ADDR_TV, 0x0000, "HdmiCecLocalDevicePlaybackTest");
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 775e88750cef..31cf59ee7bde 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -63,7 +63,7 @@ import java.util.ArrayList;
@RunWith(JUnit4.class)
public class HdmiControlServiceTest {
- private class HdmiCecLocalDeviceMyDevice extends HdmiCecLocalDevice {
+ private class HdmiCecLocalDeviceMyDevice extends HdmiCecLocalDeviceSource {
private boolean mCanGoToStandby;
private boolean mIsStandby;
@@ -405,6 +405,83 @@ public class HdmiControlServiceTest {
assertThat(callback2.mVolumeControlEnabled).isTrue();
}
+ @Test
+ public void setActiveSource_localDevice_playback() {
+ int physicalAddress = 0x1000;
+ mNativeWrapper.setPhysicalAddress(physicalAddress);
+
+ mHdmiControlService.setActiveSource(mMyPlaybackDevice.mAddress, physicalAddress,
+ "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+ mMyPlaybackDevice.mAddress);
+ assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
+ physicalAddress);
+ assertThat(mMyPlaybackDevice.mIsActiveSource).isTrue();
+ assertThat(mMyAudioSystemDevice.mIsActiveSource).isFalse();
+ }
+
+ @Test
+ public void setActiveSource_localDevice_audio() {
+ int physicalAddress = 0x1000;
+ mNativeWrapper.setPhysicalAddress(physicalAddress);
+
+ mHdmiControlService.setActiveSource(mMyAudioSystemDevice.mAddress, physicalAddress,
+ "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+ mMyAudioSystemDevice.mAddress);
+ assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
+ physicalAddress);
+ assertThat(mMyPlaybackDevice.mIsActiveSource).isFalse();
+ assertThat(mMyAudioSystemDevice.mIsActiveSource).isTrue();
+ }
+
+ @Test
+ public void setActiveSource_remoteDevice() {
+ int physicalAddress = 0x1000;
+ mNativeWrapper.setPhysicalAddress(physicalAddress);
+
+ mHdmiControlService.setActiveSource(Constants.ADDR_TV, 0x0000, "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+ Constants.ADDR_TV);
+ assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(0x000);
+ assertThat(mMyPlaybackDevice.mIsActiveSource).isFalse();
+ assertThat(mMyAudioSystemDevice.mIsActiveSource).isFalse();
+ }
+
+ @Test
+ public void setActiveSource_nonCecDevice() {
+ int physicalAddress = 0x1000;
+ mNativeWrapper.setPhysicalAddress(physicalAddress);
+
+ mHdmiControlService.setActiveSource(Constants.ADDR_INVALID, 0x1234,
+ "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+ Constants.ADDR_INVALID);
+ assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(0x1234);
+ assertThat(mMyPlaybackDevice.mIsActiveSource).isFalse();
+ assertThat(mMyAudioSystemDevice.mIsActiveSource).isFalse();
+ }
+
+ @Test
+ public void setActiveSource_unknown() {
+ int physicalAddress = 0x1000;
+ mNativeWrapper.setPhysicalAddress(physicalAddress);
+
+ mHdmiControlService.setActiveSource(Constants.ADDR_INVALID,
+ Constants.INVALID_PHYSICAL_ADDRESS, "HdmiControlServiceTest");
+
+ assertThat(mHdmiControlService.getLocalActiveSource().logicalAddress).isEqualTo(
+ Constants.ADDR_INVALID);
+ assertThat(mHdmiControlService.getLocalActiveSource().physicalAddress).isEqualTo(
+ Constants.INVALID_PHYSICAL_ADDRESS);
+ assertThat(mMyPlaybackDevice.mIsActiveSource).isFalse();
+ assertThat(mMyAudioSystemDevice.mIsActiveSource).isFalse();
+ }
+
private static class VolumeControlFeatureCallback extends
IHdmiCecVolumeControlFeatureListener.Stub {
boolean mCallbackReceived = false;
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index b2512d3ed8ca..eec7d125d219 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -379,7 +379,7 @@ public class AppsFilterTest {
}
@Test
- public void testForceQueryable_DoesntFilter() throws Exception {
+ public void testForceQueryable_SystemDoesntFilter() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor);
@@ -387,7 +387,8 @@ public class AppsFilterTest {
appsFilter.onSystemReady();
PackageSetting target = simulateAddPackage(appsFilter,
- pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_APPID);
+ pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_APPID,
+ setting -> setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM));
PackageSetting calling = simulateAddPackage(appsFilter,
pkg("com.some.other.package"), DUMMY_CALLING_APPID);
@@ -395,6 +396,24 @@ public class AppsFilterTest {
SYSTEM_USER));
}
+
+ @Test
+ public void testForceQueryable_NonSystemFilters() throws Exception {
+ final AppsFilter appsFilter =
+ new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+ mMockExecutor);
+ simulateAddBasicAndroid(appsFilter);
+ appsFilter.onSystemReady();
+
+ PackageSetting target = simulateAddPackage(appsFilter,
+ pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_APPID);
+ PackageSetting calling = simulateAddPackage(appsFilter,
+ pkg("com.some.other.package"), DUMMY_CALLING_APPID);
+
+ assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+ SYSTEM_USER));
+ }
+
@Test
public void testForceQueryableByDevice_SystemCaller_DoesntFilter() throws Exception {
final AppsFilter appsFilter =
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 2d834ac57f51..a5585c0f02b1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -26,8 +26,6 @@ import static android.view.InsetsState.ITYPE_TOP_GESTURES;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
-import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
-import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
@@ -475,7 +473,6 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
mWindow.mAttrs.setFitInsetsTypes(
mWindow.mAttrs.getFitInsetsTypes() & ~Type.statusBars());
addWindow(mWindow);
@@ -497,9 +494,9 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
mDisplayContent.getInsetsPolicy().getInsetsForDispatch(mWindow)
.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
+ mWindow.getRequestedInsetsState().getSource(ITYPE_STATUS_BAR).setVisible(false);
addWindow(mWindow);
mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
@@ -519,9 +516,9 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
mDisplayContent.getInsetsPolicy().getInsetsForDispatch(mWindow)
.getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false);
+ mWindow.getRequestedInsetsState().getSource(ITYPE_STATUS_BAR).setVisible(false);
mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
addWindow(mWindow);
@@ -585,7 +582,6 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
mWindow.mAttrs.setFitInsetsTypes(
mWindow.mAttrs.getFitInsetsTypes() & ~Type.statusBars());
addWindow(mWindow);
@@ -626,7 +622,6 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
- mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
mWindow.mAttrs.setFitInsetsTypes(
mWindow.mAttrs.getFitInsetsTypes() & ~Type.statusBars());
mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 54c7f271e81b..9954f484f0a6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -28,6 +28,8 @@ import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -447,6 +449,31 @@ public class RecentTasksTest extends WindowTestsBase {
}
@Test
+ public void testRemoveAffinityTask() {
+ // Add task to recents
+ final String taskAffinity = "affinity";
+ final int uid = 10123;
+ final Task task1 = createTaskBuilder(".Task1").setStack(mStack).build();
+ task1.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid, LAUNCH_MULTIPLE);
+ mRecentTasks.add(task1);
+
+ // Add another task to recents, and make sure the previous task was removed.
+ final Task task2 = createTaskBuilder(".Task2").setStack(mStack).build();
+ task2.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid, LAUNCH_MULTIPLE);
+ mRecentTasks.add(task2);
+ assertEquals(1, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
+ true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().size());
+
+ // Add another single-instance task to recents, and make sure no task is removed.
+ final Task task3 = createTaskBuilder(".Task3").setStack(mStack).build();
+ task3.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid,
+ LAUNCH_SINGLE_INSTANCE);
+ mRecentTasks.add(task3);
+ assertEquals(2, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
+ true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().size());
+ }
+
+ @Test
public void testAddTasksHomeClearUntrackedTasks_expectFinish() {
// There may be multiple tasks with the same base intent by flags (FLAG_ACTIVITY_NEW_TASK |
// FLAG_ACTIVITY_MULTIPLE_TASK). If the previous task is still active, it should be removed
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 952997efa0d4..943d78398879 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -18,7 +18,7 @@ android_test {
name: "FlickerTests",
srcs: ["src/**/*.java", "src/**/*.kt"],
manifest: "AndroidManifest.xml",
- test_config: "AndroidTest.xml",
+ test_config: "AndroidTestPhysicalDevices.xml",
platform_apis: true,
certificate: "platform",
test_suites: ["device-tests"],
@@ -33,3 +33,24 @@ android_test {
"launcher-aosp-tapl"
],
}
+
+
+android_test {
+ name: "FlickerTestsVirtual",
+ srcs: ["src/**/*.java", "src/**/*.kt"],
+ manifest: "AndroidManifest.xml",
+ test_config: "AndroidTestVirtualDevices.xml",
+ platform_apis: true,
+ certificate: "platform",
+ test_suites: ["device-tests"],
+ libs: ["android.test.runner"],
+ static_libs: [
+ "androidx.test.ext.junit",
+ "flickertestapplib",
+ "flickerlib",
+ "truth-prebuilt",
+ "app-helpers-core",
+ "launcher-helper-lib",
+ "launcher-aosp-tapl"
+ ],
+} \ No newline at end of file
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTestPhysicalDevices.xml
index 68c99a35e5d0..16504389098c 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTestPhysicalDevices.xml
@@ -27,6 +27,7 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.server.wm.flicker"/>
+ <option name="include-annotation" value="androidx.test.filters.RequiresDevice" />
<option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
<option name="shell-timeout" value="6600s" />
<option name="test-timeout" value="6000s" />
diff --git a/tests/FlickerTests/AndroidTestVirtualDevices.xml b/tests/FlickerTests/AndroidTestVirtualDevices.xml
new file mode 100644
index 000000000000..222212a74cd0
--- /dev/null
+++ b/tests/FlickerTests/AndroidTestVirtualDevices.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright 2018 Google Inc. All Rights Reserved.
+ -->
+<configuration description="Runs WindowManager Flicker Tests">
+ <option name="test-tag" value="FlickerTests" />
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- keeps the screen on during tests -->
+ <option name="screen-always-on" value="on" />
+ <!-- prevents the phone from restarting -->
+ <option name="force-skip-system-props" value="true" />
+ <!-- set WM tracing verbose level to all -->
+ <option name="run-command" value="cmd window tracing level all" />
+ <!-- inform WM to log all transactions -->
+ <option name="run-command" value="cmd window tracing transaction" />
+ <!-- restart launcher to activate TAPL -->
+ <option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.DeviceCleaner">
+ <!-- reboot the device to teardown any crashed tests -->
+ <option name="cleanup-action" value="REBOOT" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true"/>
+ <option name="test-file-name" value="FlickerTests.apk"/>
+ <option name="test-file-name" value="FlickerTestApp.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.server.wm.flicker"/>
+ <option name="exclude-annotation" value="androidx.test.filters.RequiresDevice" />
+ <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
+ <option name="shell-timeout" value="6600s" />
+ <option name="test-timeout" value="6000s" />
+ <option name="hidden-api-checks" value="false" />
+ </test>
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/storage/emulated/0/Android/data/com.android.server.wm.flicker/files" />
+ <option name="collect-on-run-ended-only" value="true" />
+ <option name="clean-up" value="true" />
+ </metrics_collector>
+</configuration>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index 80d039475fab..404c7891bcad 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -39,7 +39,7 @@ import org.junit.runners.Parameterized
* Test IME window closing back to app window transitions.
* To run this test: `atest FlickerTests:CloseImeWindowToAppTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class CloseImeAutoOpenWindowToAppTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index c0658fe4422e..b64811b2767d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -39,7 +39,7 @@ import org.junit.runners.Parameterized
* Test IME window closing back to app window transitions.
* To run this test: `atest FlickerTests:CloseImeWindowToAppTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class CloseImeAutoOpenWindowToHomeTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index 67c46d3f4722..0940c192517e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.NonRotationTestBase
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -39,7 +39,7 @@ import org.junit.runners.Parameterized
* Test IME window closing back to app window transitions.
* To run this test: `atest FlickerTests:CloseImeWindowToAppTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
open class CloseImeWindowToAppTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index dcf308533ee6..c2e87dbbf24b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.NonRotationTestBase
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -40,7 +40,7 @@ import org.junit.runners.Parameterized
* Test IME window closing to home transitions.
* To run this test: `atest FlickerTests:CloseImeWindowToHomeTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
open class CloseImeWindowToHomeTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index 5874a0736d85..11ccb69c46cf 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.NonRotationTestBase
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -39,7 +39,7 @@ import org.junit.runners.Parameterized
* Test IME window opening transitions.
* To run this test: `atest FlickerTests:OpenImeWindowTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenImeWindowTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 62337e9bff34..254209aee450 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.launch
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
@@ -38,7 +38,7 @@ import org.junit.runners.Parameterized
* Test cold launch app from launcher.
* To run this test: `atest FlickerTests:OpenAppColdTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenAppColdTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 57d6127b1cd1..dda41a3021a0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.launch
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.StandardAppHelper
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.focusChanges
@@ -39,7 +39,7 @@ import org.junit.runners.Parameterized
* Test warm launch app.
* To run this test: `atest FlickerTests:OpenAppWarmTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenAppWarmTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt
index 4acd97553bc0..9cfc03304fe7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt
@@ -18,7 +18,7 @@ package com.android.server.wm.flicker.pip
import android.view.Surface
import androidx.test.filters.FlakyTest
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.closePipWindow
import com.android.server.wm.flicker.helpers.expandPipWindow
@@ -41,7 +41,7 @@ import org.junit.runners.Parameterized
* Test Pip launch.
* To run this test: `atest FlickerTests:PipToAppTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 152738416)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
index 04c2f59118bd..deccc908961d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
@@ -18,7 +18,7 @@ package com.android.server.wm.flicker.pip
import android.view.Surface
import androidx.test.filters.FlakyTest
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.helpers.closePipWindow
@@ -42,7 +42,7 @@ import org.junit.runners.Parameterized
* Test Pip launch.
* To run this test: `atest FlickerTests:PipToAppTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 152738416)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
index b6074cd7033b..f40869c88d63 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
@@ -18,7 +18,7 @@ package com.android.server.wm.flicker.pip
import android.view.Surface
import androidx.test.filters.FlakyTest
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.helpers.closePipWindow
@@ -41,7 +41,7 @@ import org.junit.runners.Parameterized
* Test Pip launch.
* To run this test: `atest FlickerTests:PipToHomeTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 152738416)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 5e75e4a144bf..0ca150892f36 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -16,8 +16,8 @@
package com.android.server.wm.flicker.rotation
+import androidx.test.filters.RequiresDevice
import android.view.Surface
-import androidx.test.filters.LargeTest
import com.android.server.wm.flicker.NonRotationTestBase.Companion.SCREENSHOT_LAYER
import com.android.server.wm.flicker.RotationTestBase
import com.android.server.wm.flicker.StandardAppHelper
@@ -42,7 +42,7 @@ import org.junit.runners.Parameterized
* Cycle through supported app rotations.
* To run this test: `atest FlickerTest:ChangeAppRotationTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class ChangeAppRotationTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index de87b412fc90..33a823d6cfc9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -20,14 +20,13 @@ import android.content.Intent
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.view.Surface
import androidx.test.filters.FlakyTest
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.RotationTestBase
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.focusDoesNotChange
import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.stopPackage
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
@@ -48,7 +47,7 @@ import org.junit.runners.Parameterized
* Cycle through supported app rotations using seamless rotations.
* To run this test: `atest FlickerTests:SeamlessAppRotationTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 147659548)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
index 279092d716e2..c5e48d966155 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.splitscreen
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.NonRotationTestBase
import com.android.server.wm.flicker.StandardAppHelper
import com.android.server.wm.flicker.dsl.flicker
@@ -43,7 +43,7 @@ import org.junit.runners.Parameterized
* Test open app to split screen.
* To run this test: `atest FlickerTests:OpenAppToSplitScreenTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenAppToSplitScreenTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
index a08b2bfdf1fe..91211cabf45c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
@@ -21,7 +21,7 @@ import android.util.Rational
import android.view.Surface
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.FlakyTest
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.By
import com.android.server.wm.flicker.FlickerTestBase
import com.android.server.wm.flicker.StandardAppHelper
@@ -52,7 +52,7 @@ import org.junit.runners.MethodSorters
*
* Currently it runs only in 0 degrees because of b/156100803
*/
-@LargeTest
+@RequiresDevice
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 159096424)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
index e2d78399b35b..5c7dcd901a41 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.splitscreen
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.NonRotationTestBase
import com.android.server.wm.flicker.StandardAppHelper
import com.android.server.wm.flicker.dsl.flicker
@@ -43,7 +43,7 @@ import org.junit.runners.Parameterized
* Test open app to split screen.
* To run this test: `atest FlickerTests:SplitScreenToLauncherTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class SplitScreenToLauncherTest(
diff --git a/tests/SilkFX/Android.bp b/tests/SilkFX/Android.bp
index ca0a091e65bb..92e3efa7fd55 100644
--- a/tests/SilkFX/Android.bp
+++ b/tests/SilkFX/Android.bp
@@ -19,4 +19,10 @@ android_test {
srcs: ["**/*.java", "**/*.kt"],
platform_apis: true,
certificate: "platform",
+ static_libs: [
+ "androidx.core_core",
+ "androidx.appcompat_appcompat",
+ "com.google.android.material_material",
+ "androidx-constraintlayout_constraintlayout",
+ ],
}
diff --git a/tests/SilkFX/AndroidManifest.xml b/tests/SilkFX/AndroidManifest.xml
index ca9550a9eeab..050e9c33aeac 100644
--- a/tests/SilkFX/AndroidManifest.xml
+++ b/tests/SilkFX/AndroidManifest.xml
@@ -39,5 +39,8 @@
<activity android:name=".hdr.GlowActivity"
android:label="Glow Examples"/>
+ <activity android:name=".materials.GlassActivity"
+ android:label="Glass Examples"/>
+
</application>
</manifest>
diff --git a/tests/SilkFX/res/drawable-hdpi/background1.jpeg b/tests/SilkFX/res/drawable-hdpi/background1.jpeg
new file mode 100644
index 000000000000..dcdfa7b850bc
--- /dev/null
+++ b/tests/SilkFX/res/drawable-hdpi/background1.jpeg
Binary files differ
diff --git a/tests/SilkFX/res/drawable-hdpi/background2.jpeg b/tests/SilkFX/res/drawable-hdpi/background2.jpeg
new file mode 100644
index 000000000000..dc7ce84e6784
--- /dev/null
+++ b/tests/SilkFX/res/drawable-hdpi/background2.jpeg
Binary files differ
diff --git a/tests/SilkFX/res/drawable-hdpi/background3.jpeg b/tests/SilkFX/res/drawable-hdpi/background3.jpeg
new file mode 100644
index 000000000000..12b3429e3920
--- /dev/null
+++ b/tests/SilkFX/res/drawable-hdpi/background3.jpeg
Binary files differ
diff --git a/tests/SilkFX/res/drawable-hdpi/noise.png b/tests/SilkFX/res/drawable-hdpi/noise.png
new file mode 100644
index 000000000000..053995dad760
--- /dev/null
+++ b/tests/SilkFX/res/drawable-hdpi/noise.png
Binary files differ
diff --git a/tests/SilkFX/res/layout/activity_glass.xml b/tests/SilkFX/res/layout/activity_glass.xml
new file mode 100644
index 000000000000..85dab9315197
--- /dev/null
+++ b/tests/SilkFX/res/layout/activity_glass.xml
@@ -0,0 +1,246 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+** Copyright 2012, 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.
+-->
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MainActivity">
+
+ <ImageView
+ android:id="@+id/background"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:scaleType="matrix"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:srcCompat="@drawable/background1" />
+
+ <com.android.test.silkfx.materials.GlassView
+ android:id="@+id/materialView"
+ android:layout_width="0dp"
+ android:layout_height="180dp"
+ android:layout_marginEnd="64dp"
+ android:layout_marginStart="64dp"
+ app:layout_constraintBottom_toTopOf="@+id/bottomPanel"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:id="@+id/bottomPanel"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/colorBackground"
+ android:paddingTop="24dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent">
+
+ <SeekBar
+ android:id="@+id/materialOpacity"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginBottom="16dp"
+ android:max="100"
+ android:progress="12"
+ app:layout_constraintBottom_toTopOf="@+id/scrimOpacityTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/blurRadius"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginStart="12dp"
+ android:max="150"
+ android:progress="50"
+ app:layout_constraintBottom_toTopOf="@+id/materialOpacityTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/scrimOpacity"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginBottom="16dp"
+ android:max="100"
+ android:progress="50"
+ app:layout_constraintBottom_toTopOf="@+id/noiseOpacityTitle"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <SeekBar
+ android:id="@+id/noiseOpacity"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginBottom="24dp"
+ android:max="100"
+ android:progress="5"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.0"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/scrimOpacityTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Scrim Opacity"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/scrimOpacity"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/materialOpacityTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Material Opacity"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/materialOpacity"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/blurRadiusTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Blur Radius"
+ android:textColor="@android:color/white"
+ app:layout_constraintBottom_toTopOf="@+id/blurRadius"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/noiseOpacityTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:textColor="@android:color/white"
+ android:text="Noise Opacity"
+ app:layout_constraintBottom_toTopOf="@+id/noiseOpacity"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <ImageView
+ android:id="@+id/background1"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="16dp"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onBackgroundClick"
+ android:scaleType="centerCrop"
+ app:layout_constraintBottom_toTopOf="@+id/lightMaterialSwitch"
+ app:layout_constraintStart_toStartOf="parent"
+ android:src="@drawable/background1" />
+
+ <ImageView
+ android:id="@+id/background2"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="8dp"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onBackgroundClick"
+ android:scaleType="centerCrop"
+ app:layout_constraintBottom_toBottomOf="@+id/background1"
+ app:layout_constraintStart_toEndOf="@+id/background1"
+ android:src="@drawable/background2" />
+
+ <ImageView
+ android:id="@+id/background3"
+ android:layout_width="64dp"
+ android:layout_height="64dp"
+ android:layout_marginStart="8dp"
+ android:scaleType="centerCrop"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ android:clickable="true"
+ android:onClick="onBackgroundClick"
+ app:layout_constraintBottom_toBottomOf="@+id/background1"
+ app:layout_constraintStart_toEndOf="@+id/background2"
+ android:src="@drawable/background3" />
+
+ <Switch
+ android:id="@+id/lightMaterialSwitch"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="8dp"
+ android:text="Light Material"
+ app:layout_constraintBottom_toTopOf="@+id/blurRadiusTitle"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/blurRadiusValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/blurRadiusTitle"
+ app:layout_constraintStart_toEndOf="@+id/blurRadiusTitle" />
+
+ <TextView
+ android:id="@+id/materialOpacityValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/materialOpacityTitle"
+ app:layout_constraintStart_toEndOf="@+id/materialOpacityTitle" />
+
+ <TextView
+ android:id="@+id/noiseOpacityValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/noiseOpacityTitle"
+ app:layout_constraintStart_toEndOf="@+id/noiseOpacityTitle" />
+
+
+ <TextView
+ android:id="@+id/scrimOpacityValue"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="TextView"
+ android:layout_marginLeft="8dp"
+ app:layout_constraintBottom_toBottomOf="@+id/scrimOpacityTitle"
+ app:layout_constraintStart_toEndOf="@+id/scrimOpacityTitle" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+
+</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/Main.kt b/tests/SilkFX/src/com/android/test/silkfx/Main.kt
index 76e62a6c8cff..9ed8d2f5edf7 100644
--- a/tests/SilkFX/src/com/android/test/silkfx/Main.kt
+++ b/tests/SilkFX/src/com/android/test/silkfx/Main.kt
@@ -29,6 +29,7 @@ import com.android.test.silkfx.app.CommonDemoActivity
import com.android.test.silkfx.app.EXTRA_LAYOUT
import com.android.test.silkfx.app.EXTRA_TITLE
import com.android.test.silkfx.hdr.GlowActivity
+import com.android.test.silkfx.materials.GlassActivity
import kotlin.reflect.KClass
class Demo(val name: String, val makeIntent: (Context) -> Intent) {
@@ -48,6 +49,9 @@ private val AllDemos = listOf(
DemoGroup("HDR", listOf(
Demo("Glow", GlowActivity::class),
Demo("Blingy Notifications", R.layout.bling_notifications)
+ )),
+ DemoGroup("Materials", listOf(
+ Demo("Glass", GlassActivity::class)
))
)
diff --git a/tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt
new file mode 100644
index 000000000000..6f5ddacb2733
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassActivity.kt
@@ -0,0 +1,126 @@
+/*
+ * 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.test.silkfx.materials
+
+import android.app.Activity
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.Color
+import android.os.Bundle
+import android.util.TypedValue
+import android.view.View
+import android.widget.ImageView
+import android.widget.SeekBar
+import android.widget.Switch
+import android.widget.TextView
+import com.android.test.silkfx.R
+
+class GlassActivity : Activity(), SeekBar.OnSeekBarChangeListener {
+
+ lateinit var backgroundButton1: ImageView
+ lateinit var backgroundButton2: ImageView
+ lateinit var backgroundButton3: ImageView
+ lateinit var backgroundView: ImageView
+ lateinit var materialView: GlassView
+ lateinit var lightMaterialSwitch: Switch
+ lateinit var noiseOpacitySeekBar: SeekBar
+ lateinit var materialOpacitySeekBar: SeekBar
+ lateinit var scrimOpacitySeekBar: SeekBar
+ lateinit var blurRadiusSeekBar: SeekBar
+ lateinit var noiseOpacityValue: TextView
+ lateinit var materialOpacityValue: TextView
+ lateinit var scrimOpacityValue: TextView
+ lateinit var blurRadiusValue: TextView
+
+ lateinit var background: Bitmap
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_glass)
+ backgroundButton1 = requireViewById(R.id.background1)
+ backgroundButton2 = requireViewById(R.id.background2)
+ backgroundButton3 = requireViewById(R.id.background3)
+ backgroundView = requireViewById(R.id.background)
+ lightMaterialSwitch = requireViewById(R.id.lightMaterialSwitch)
+ materialView = requireViewById(R.id.materialView)
+ materialOpacitySeekBar = requireViewById(R.id.materialOpacity)
+ blurRadiusSeekBar = requireViewById(R.id.blurRadius)
+ noiseOpacitySeekBar = requireViewById(R.id.noiseOpacity)
+ scrimOpacitySeekBar = requireViewById(R.id.scrimOpacity)
+ noiseOpacityValue = requireViewById(R.id.noiseOpacityValue)
+ materialOpacityValue = requireViewById(R.id.materialOpacityValue)
+ scrimOpacityValue = requireViewById(R.id.scrimOpacityValue)
+ blurRadiusValue = requireViewById(R.id.blurRadiusValue)
+
+ background = BitmapFactory.decodeResource(resources, R.drawable.background1)
+ backgroundView.setImageBitmap(background)
+ materialView.backgroundBitmap = background
+
+ blurRadiusSeekBar.setOnSeekBarChangeListener(this)
+ materialOpacitySeekBar.setOnSeekBarChangeListener(this)
+ noiseOpacitySeekBar.setOnSeekBarChangeListener(this)
+ scrimOpacitySeekBar.setOnSeekBarChangeListener(this)
+
+ arrayOf(blurRadiusSeekBar, materialOpacitySeekBar, noiseOpacitySeekBar,
+ scrimOpacitySeekBar).forEach {
+ it.setOnSeekBarChangeListener(this)
+ onProgressChanged(it, it.progress, fromUser = false)
+ }
+
+ lightMaterialSwitch.setOnCheckedChangeListener { _, isChecked ->
+ materialView.color = if (isChecked) Color.WHITE else Color.BLACK
+ }
+ }
+
+ override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
+ when (seekBar) {
+ blurRadiusSeekBar -> {
+ materialView.blurRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ progress.toFloat(), resources.displayMetrics)
+ blurRadiusValue.text = progress.toString()
+ }
+ materialOpacitySeekBar -> {
+ materialView.materialOpacity = progress / seekBar.max.toFloat()
+ materialOpacityValue.text = progress.toString()
+ }
+ noiseOpacitySeekBar -> {
+ materialView.noiseOpacity = progress / seekBar.max.toFloat()
+ noiseOpacityValue.text = progress.toString()
+ }
+ scrimOpacitySeekBar -> {
+ materialView.scrimOpacity = progress / seekBar.max.toFloat()
+ scrimOpacityValue.text = progress.toString()
+ }
+ else -> throw IllegalArgumentException("Unknown seek bar")
+ }
+ }
+
+ override fun onStartTrackingTouch(seekBar: SeekBar?) {}
+ override fun onStopTrackingTouch(seekBar: SeekBar?) {}
+
+ fun onBackgroundClick(view: View) {
+ val resource = when (view) {
+ backgroundButton1 -> R.drawable.background1
+ backgroundButton2 -> R.drawable.background2
+ backgroundButton3 -> R.drawable.background3
+ else -> throw IllegalArgumentException("Invalid button")
+ }
+
+ background = BitmapFactory.decodeResource(resources, resource)
+ backgroundView.setImageBitmap(background)
+ materialView.backgroundBitmap = background
+ }
+} \ No newline at end of file
diff --git a/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
new file mode 100644
index 000000000000..e100959908c3
--- /dev/null
+++ b/tests/SilkFX/src/com/android/test/silkfx/materials/GlassView.kt
@@ -0,0 +1,117 @@
+/*
+ * 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.test.silkfx.materials
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.BitmapShader
+import android.graphics.BlendMode
+import android.graphics.BlurShader
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Outline
+import android.graphics.Paint
+import android.graphics.Rect
+import android.graphics.Shader
+import android.util.AttributeSet
+import android.view.View
+import android.view.ViewOutlineProvider
+import com.android.test.silkfx.R
+
+class GlassView(context: Context, attributeSet: AttributeSet) : View(context, attributeSet) {
+
+ var noise = BitmapFactory.decodeResource(resources, R.drawable.noise)
+ var materialPaint = Paint()
+ var scrimPaint = Paint()
+ var noisePaint = Paint()
+ var blurPaint = Paint()
+
+ val src = Rect()
+ val dst = Rect()
+
+ var backgroundBitmap: Bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
+ set(value) {
+ field = value
+ invalidate()
+ }
+
+ var noiseOpacity = 0.0f
+ set(value) {
+ field = value
+ noisePaint.alpha = (value * 255).toInt()
+ invalidate()
+ }
+
+ var materialOpacity = 0.0f
+ set(value) {
+ field = value
+ materialPaint.alpha = (value * 255).toInt()
+ invalidate()
+ }
+
+ var scrimOpacity = 0.5f
+ set(value) {
+ field = value
+ scrimPaint.alpha = (value * 255).toInt()
+ invalidate()
+ }
+
+ var color = Color.BLACK
+ set(value) {
+ field = value
+ var alpha = materialPaint.alpha
+ materialPaint.color = color
+ materialPaint.alpha = alpha
+
+ alpha = scrimPaint.alpha
+ scrimPaint.color = color
+ scrimPaint.alpha = alpha
+ invalidate()
+ }
+
+ var blurRadius = 150f
+ set(value) {
+ field = value
+ blurPaint.shader = BlurShader(value, value, null)
+ invalidate()
+ }
+
+ init {
+ materialPaint.blendMode = BlendMode.SOFT_LIGHT
+ noisePaint.blendMode = BlendMode.SOFT_LIGHT
+ noisePaint.shader = BitmapShader(noise, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT)
+ scrimPaint.alpha = (scrimOpacity * 255).toInt()
+ noisePaint.alpha = (noiseOpacity * 255).toInt()
+ materialPaint.alpha = (materialOpacity * 255).toInt()
+ blurPaint.shader = BlurShader(blurRadius, blurRadius, null)
+ outlineProvider = object : ViewOutlineProvider() {
+ override fun getOutline(view: View?, outline: Outline?) {
+ outline?.setRoundRect(Rect(0, 0, width, height), 100f)
+ }
+ }
+ clipToOutline = true
+ }
+
+ override fun onDraw(canvas: Canvas?) {
+ src.set(left, top, right, bottom)
+ dst.set(0, 0, width, height)
+ canvas?.drawBitmap(backgroundBitmap, src, dst, blurPaint)
+ canvas?.drawRect(dst, materialPaint)
+ canvas?.drawRect(dst, noisePaint)
+ canvas?.drawRect(dst, scrimPaint)
+ }
+} \ No newline at end of file
diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp
index 5ac9dfd2a557..0aca13e95a52 100644
--- a/tools/validatekeymaps/Main.cpp
+++ b/tools/validatekeymaps/Main.cpp
@@ -96,21 +96,19 @@ static bool validateFile(const char* filename) {
return false;
case FILETYPE_KEYLAYOUT: {
- sp<KeyLayoutMap> map;
- status_t status = KeyLayoutMap::load(filename, &map);
- if (status) {
- error("Error %d parsing key layout file.\n\n", status);
+ base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(filename);
+ if (!ret) {
+ error("Error %s parsing key layout file.\n\n", ret.error().message().c_str());
return false;
}
break;
}
case FILETYPE_KEYCHARACTERMAP: {
- sp<KeyCharacterMap> map;
- status_t status = KeyCharacterMap::load(filename,
- KeyCharacterMap::FORMAT_ANY, &map);
- if (status) {
- error("Error %d parsing key character map file.\n\n", status);
+ base::Result<std::shared_ptr<KeyCharacterMap>> ret = KeyCharacterMap::load(filename,
+ KeyCharacterMap::FORMAT_ANY);
+ if (!ret) {
+ error("Error %s parsing key character map file.\n\n", ret.error().message().c_str());
return false;
}
break;