summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt1
-rw-r--r--core/java/android/app/IActivityManager.aidl10
-rw-r--r--core/java/android/net/SocketKeepalive.java6
-rw-r--r--core/java/android/os/BinderProxy.java14
-rw-r--r--core/java/android/os/Process.java2
-rw-r--r--core/jni/android_util_Process.cpp17
-rw-r--r--core/jni/android_view_KeyCharacterMap.cpp54
-rw-r--r--core/jni/android_view_KeyCharacterMap.h2
-rw-r--r--media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java37
-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/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/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/CarNavigationBar.java6
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java6
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java148
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/statusbar/UserNameViewController.java132
-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.java19
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java48
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/statusbar/UserNameViewControllerTest.java155
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java24
-rw-r--r--packages/SystemUI/res/layout-land-television/volume_dialog.xml9
-rw-r--r--packages/SystemUI/res/layout-land-television/volume_dialog_row.xml38
-rw-r--r--packages/SystemUI/res/layout/controls_management.xml5
-rw-r--r--packages/SystemUI/res/layout/controls_management_favorites.xml2
-rw-r--r--packages/SystemUI/res/layout/controls_structure_page.xml2
-rw-r--r--packages/SystemUI/res/values-land-television/dimens.xml5
-rw-r--r--packages/SystemUI/res/values-land/dimens.xml11
-rw-r--r--packages/SystemUI/res/values-television/integers.xml7
-rw-r--r--packages/SystemUI/res/values/dimens.xml4
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java70
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java172
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java54
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java10
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java4
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java8
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java48
-rw-r--r--services/core/java/com/android/server/am/CachedAppOptimizer.java77
-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/biometrics/sensors/AuthenticationClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java5
-rw-r--r--services/core/java/com/android/server/connectivity/KeepaliveTracker.java50
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java16
-rw-r--r--services/core/java/com/android/server/pm/AppsFilter.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java13
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java15
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java3
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java13
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java34
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java16
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java11
-rw-r--r--services/core/java/com/android/server/wm/LockTaskController.java2
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java7
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java4
-rw-r--r--services/core/java/com/android/server/wm/Task.java58
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java10
-rw-r--r--services/core/jni/Android.bp1
-rw-r--r--services/core/jni/com_android_server_am_CachedAppOptimizer.cpp18
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp15
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java23
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java28
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java12
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java2
-rw-r--r--tools/validatekeymaps/Main.cpp16
-rw-r--r--wifi/api/current.txt1
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkSuggestion.java35
-rw-r--r--wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java27
101 files changed, 2428 insertions, 843 deletions
diff --git a/api/current.txt b/api/current.txt
index e5baa7c07cd5..a1629f1a937e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -31665,6 +31665,7 @@ package android.net.wifi {
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setBssid(@NonNull android.net.MacAddress);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setCredentialSharedWithUser(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsAppInteractionRequired(boolean);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsEnhancedMacRandomizationEnabled(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsEnhancedOpen(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsHiddenSsid(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsInitialAutojoinEnabled(boolean);
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 0a47248e3b70..cd9e02d30d05 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -695,4 +695,14 @@ interface IActivityManager {
* android.permission.RESET_APP_ERRORS.
*/
void resetAppErrors();
+
+ /**
+ * Control the app freezer state. Returns true in case of success, false if the operation
+ * didn't succeed (for example, when the app freezer isn't supported).
+ * Handling the freezer state via this method is reentrant, that is it can be
+ * disabled and re-enabled multiple times in parallel. As long as there's a 1:1 disable to
+ * enable match, the freezer is re-enabled at last enable only.
+ * @param enable set it to true to enable the app freezer, false to disable it.
+ */
+ boolean enableAppFreezer(in boolean enable);
}
diff --git a/core/java/android/net/SocketKeepalive.java b/core/java/android/net/SocketKeepalive.java
index 46aef10258d9..a7dce18a4ff9 100644
--- a/core/java/android/net/SocketKeepalive.java
+++ b/core/java/android/net/SocketKeepalive.java
@@ -85,6 +85,12 @@ public abstract class SocketKeepalive implements AutoCloseable {
public static final int ERROR_INVALID_SOCKET = -25;
/** The target socket is not idle. */
public static final int ERROR_SOCKET_NOT_IDLE = -26;
+ /**
+ * The stop reason is uninitialized. This should only be internally used as initial state
+ * of stop reason, instead of propagating to application.
+ * @hide
+ */
+ public static final int ERROR_STOP_REASON_UNINITIALIZED = -27;
/** The device does not support this request. */
public static final int ERROR_UNSUPPORTED = -30;
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index 683993f762c0..0185ba444ca4 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -18,6 +18,7 @@ package android.os;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.util.Log;
import android.util.SparseIntArray;
@@ -255,7 +256,12 @@ public final class BinderProxy implements IBinder {
// out of system_server to all processes hosting binder objects it holds a reference to;
// since some of those processes might be frozen, we don't want to block here
// forever. Disable the freezer.
- Process.enableFreezer(false);
+ try {
+ ActivityManager.getService().enableAppFreezer(false);
+ } catch (RemoteException e) {
+ Log.e(Binder.TAG, "RemoteException while disabling app freezer");
+ }
+
for (WeakReference<BinderProxy> weakRef : proxiesToQuery) {
BinderProxy bp = weakRef.get();
String key;
@@ -278,7 +284,11 @@ public final class BinderProxy implements IBinder {
counts.put(key, i + 1);
}
}
- Process.enableFreezer(true);
+ try {
+ ActivityManager.getService().enableAppFreezer(true);
+ } catch (RemoteException e) {
+ Log.e(Binder.TAG, "RemoteException while re-enabling app freezer");
+ }
Map.Entry<String, Integer>[] sorted = counts.entrySet().toArray(
new Map.Entry[counts.size()]);
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index a4077fbee892..efea9537c4cf 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -947,7 +947,7 @@ public class Process {
/**
* Enable or disable the freezer. When enable == false all frozen processes are unfrozen,
- * but aren't removed from the freezer. Processes can still be added or removed
+ * but aren't removed from the freezer. While in this state, processes can be added or removed
* by using setProcessFrozen, but they won't actually be frozen until the freezer is enabled
* again. If enable == true the freezer is enabled again, and all processes
* in the freezer (including the ones added while the freezer was disabled) are frozen.
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index cbcbe7f11390..c51f334f1f2e 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -372,22 +372,6 @@ void android_os_Process_setProcessFrozen(
}
}
-void android_os_Process_enableFreezer(
- JNIEnv *env, jobject clazz, jboolean enable)
-{
- bool success = true;
-
- if (enable) {
- success = SetTaskProfiles(0, {"FreezerFrozen"}, true);
- } else {
- success = SetTaskProfiles(0, {"FreezerThawed"}, true);
- }
-
- if (!success) {
- jniThrowException(env, "java/lang/RuntimeException", "Unknown error");
- }
-}
-
jint android_os_Process_getProcessGroup(JNIEnv* env, jobject clazz, jint pid)
{
SchedPolicy sp;
@@ -1424,7 +1408,6 @@ static const JNINativeMethod methods[] = {
{"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
{"sendSignalQuiet", "(II)V", (void*)android_os_Process_sendSignalQuiet},
{"setProcessFrozen", "(IIZ)V", (void*)android_os_Process_setProcessFrozen},
- {"enableFreezer", "(Z)V", (void*)android_os_Process_enableFreezer},
{"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
{"getTotalMemory", "()J", (void*)android_os_Process_getTotalMemory},
{"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V",
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/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java
index 04909efd06b0..73e1d98cb2e2 100644
--- a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java
+++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java
@@ -132,9 +132,9 @@ public class MediaTranscodingBenchmark
Log.d(TAG,
"Transcoding completed with result: " + transcodingJob.getResult());
assertEquals(transcodingJob.getResult(), TranscodingJob.RESULT_SUCCESS);
- transcodeCompleteSemaphore.release();
transcodingTime.set(System.currentTimeMillis() - startTimeMs);
totalTimeMs.addAndGet(transcodingTime.get());
+ transcodeCompleteSemaphore.release();
});
if (job != null) {
@@ -173,9 +173,6 @@ public class MediaTranscodingBenchmark
transcode(testVideoName, transcodedVideoName);
}
- // TODO(hkuang): Enable this after b/160268606 is fixed. Transcoding video with audio takes way
- // more long time that leads to timeout failure.
- /*
@Test
public void testBenchmarkingAVCToAVCWith66FramesWithAudio() throws Exception {
String videoNameWithoutExtension = "video_1920x1080_66frame_h264_22Mbps_30fps_aac";
@@ -183,7 +180,7 @@ public class MediaTranscodingBenchmark
String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
transcode(testVideoName, transcodedVideoName);
- }*/
+ }
@Test
public void testBenchmarkingAVCToAVCWith361FramesWithoutAudio() throws Exception {
@@ -194,16 +191,14 @@ public class MediaTranscodingBenchmark
transcode(testVideoName, transcodedVideoName);
}
- // TODO(hkuang): Enable this after b/160268606 is fixed. Transcoding video with audio takes way
- // more long time that leads to timeout failure.
- /*@Test
+ @Test
public void testBenchmarkingAVCToAVCWith361FramesWithAudio() throws Exception {
String videoNameWithoutExtension = "video_1920x1080_361frame_h264_22Mbps_30fps_aac";
String testVideoName = videoNameWithoutExtension + ".mp4";
String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
transcode(testVideoName, transcodedVideoName);
- }*/
+ }
@Test
public void testBenchmarkingAVCToAVCWith943FramesWithoutAudio() throws Exception {
@@ -214,16 +209,14 @@ public class MediaTranscodingBenchmark
transcode(testVideoName, transcodedVideoName);
}
- // TODO(hkuang): Enable this after b/160268606 is fixed. Transcoding video with audio takes way
- // more long time that leads to timeout failure.
- /* @Test
+ @Test
public void testBenchmarkingAVCToAVCWith943FramesWithAudio() throws Exception {
String videoNameWithoutExtension = "video_1920x1080_943frame_h264_22Mbps_30fps_aac";
String testVideoName = videoNameWithoutExtension + ".mp4";
String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
transcode(testVideoName, transcodedVideoName);
- }*/
+ }
@Test
public void testBenchmarkingAVCToAVCWith1822FramesWithoutAudio() throws Exception {
@@ -234,16 +227,14 @@ public class MediaTranscodingBenchmark
transcode(testVideoName, transcodedVideoName);
}
- // TODO(hkuang): Enable this after b/160268606 is fixed. Transcoding video with audio takes way
- // more long time that leads to timeout failure.
- /*@Test
+ @Test
public void testBenchmarkingAVCToAVCWith1822FramesWithAudio() throws Exception {
String videoNameWithoutExtension = "video_1920x1080_1822frame_h264_22Mbps_30fps_aac";
String testVideoName = videoNameWithoutExtension + ".mp4";
String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
transcode(testVideoName, transcodedVideoName);
- }*/
+ }
@Test
public void testBenchmarkingAVCToAVCWith3648FramesWithoutAudio() throws Exception {
@@ -254,16 +245,14 @@ public class MediaTranscodingBenchmark
transcode(testVideoName, transcodedVideoName);
}
- // TODO(hkuang): Enable this after b/160268606 is fixed. Transcoding video with audio takes way
- // more long time that leads to timeout failure.
- /*@Test
+ @Test
public void testBenchmarkingAVCToAVCWith3648FramesWithAudio() throws Exception {
String videoNameWithoutExtension = "video_1920x1080_3648frame_h264_22Mbps_30fps_aac";
String testVideoName = videoNameWithoutExtension + ".mp4";
String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
transcode(testVideoName, transcodedVideoName);
- }*/
+ }
@Test
public void testBenchmarkingAVCToAVCWith11042FramesWithoutAudio() throws Exception {
@@ -274,16 +263,14 @@ public class MediaTranscodingBenchmark
transcode(testVideoName, transcodedVideoName);
}
- // TODO(hkuang): Enable this after b/160268606 is fixed. Transcoding video with audio takes way
- // more long time that leads to timeout failure.
- /*@Test
+ @Test
public void testBenchmarkingAVCToAVCWith11042FramesWithAudio() throws Exception {
String videoNameWithoutExtension = "video_1920x1080_11042frame_h264_22Mbps_30fps_aac";
String testVideoName = videoNameWithoutExtension + ".mp4";
String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
transcode(testVideoName, transcodedVideoName);
- } */
+ }
@Test
public void testBenchmarkingHEVCToAVCWith107FramesWithoutAudio() throws Exception {
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/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/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/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
index 9584850fde7c..bf8cda3b6dcb 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
@@ -340,24 +340,28 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
mTopNavigationBarView = mCarNavigationBarController.getTopBar(isDeviceSetupForUser());
if (mTopNavigationBarView != null) {
mSystemBarConfigs.insetSystemBar(SystemBarConfigs.TOP, mTopNavigationBarView);
+ mSystemBarConfigs.setInsetUpdater(SystemBarConfigs.TOP, mTopNavigationBarView);
mTopNavigationBarWindow.addView(mTopNavigationBarView);
}
mBottomNavigationBarView = mCarNavigationBarController.getBottomBar(isDeviceSetupForUser());
if (mBottomNavigationBarView != null) {
mSystemBarConfigs.insetSystemBar(SystemBarConfigs.BOTTOM, mBottomNavigationBarView);
+ mSystemBarConfigs.setInsetUpdater(SystemBarConfigs.BOTTOM, mBottomNavigationBarView);
mBottomNavigationBarWindow.addView(mBottomNavigationBarView);
}
mLeftNavigationBarView = mCarNavigationBarController.getLeftBar(isDeviceSetupForUser());
if (mLeftNavigationBarView != null) {
mSystemBarConfigs.insetSystemBar(SystemBarConfigs.LEFT, mLeftNavigationBarView);
+ mSystemBarConfigs.setInsetUpdater(SystemBarConfigs.LEFT, mLeftNavigationBarView);
mLeftNavigationBarWindow.addView(mLeftNavigationBarView);
}
mRightNavigationBarView = mCarNavigationBarController.getRightBar(isDeviceSetupForUser());
if (mRightNavigationBarView != null) {
mSystemBarConfigs.insetSystemBar(SystemBarConfigs.RIGHT, mRightNavigationBarView);
+ mSystemBarConfigs.setInsetUpdater(SystemBarConfigs.RIGHT, mRightNavigationBarView);
mRightNavigationBarWindow.addView(mRightNavigationBarView);
}
}
@@ -367,7 +371,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
}
private void attachNavBarBySide(int side) {
- switch(side) {
+ switch (side) {
case SystemBarConfigs.TOP:
if (mTopNavigationBarWindow != null) {
mWindowManager.addView(mTopNavigationBarWindow,
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/navigationbar/SystemBarConfigs.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
index b8bf825bdcc1..1418ace378d2 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
@@ -25,6 +25,7 @@ import android.util.Log;
import android.view.Gravity;
import android.view.InsetsState;
import android.view.ViewGroup;
+import android.view.WindowInsets;
import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
@@ -97,6 +98,7 @@ public class SystemBarConfigs {
populateMaps();
readConfigs();
checkEnabledBarsHaveUniqueBarTypes();
+ checkAllOverlappingBarsHaveDifferentZOrders();
checkSystemBarEnabledForNotificationPanel();
setInsetPaddingsForOverlappingCorners();
sortSystemBarSidesByZOrder();
@@ -123,16 +125,60 @@ public class SystemBarConfigs {
}
protected void insetSystemBar(@SystemBarSide int side, CarNavigationBarView view) {
+ if (mSystemBarConfigMap.get(side) == null) return;
+
int[] paddings = mSystemBarConfigMap.get(side).getPaddings();
view.setPadding(paddings[2], paddings[0], paddings[3], paddings[1]);
}
+ protected void setInsetUpdater(@SystemBarSide int side, CarNavigationBarView view) {
+ view.setOnApplyWindowInsetsListener((v, insets) -> {
+ updateInsetPaddings(side, getSystemBarsVisibility(insets));
+ insetSystemBar(side, view);
+ return insets;
+ });
+ }
+
protected List<Integer> getSystemBarSidesByZOrder() {
return mSystemBarSidesByZOrder;
}
@VisibleForTesting
- protected static int getHunZOrder() {
+ void updateInsetPaddings(@SystemBarSide int side,
+ Map<@SystemBarSide Integer, Boolean> barVisibilities) {
+ SystemBarConfig currentConfig = mSystemBarConfigMap.get(side);
+
+ if (currentConfig == null) return;
+
+ if (isHorizontalBar(side)) {
+ if (mLeftNavBarEnabled && currentConfig.getZOrder() < mSystemBarConfigMap.get(
+ LEFT).getZOrder()) {
+ currentConfig.setPaddingBySide(LEFT,
+ barVisibilities.get(LEFT) ? mSystemBarConfigMap.get(LEFT).getGirth() : 0);
+ }
+ if (mRightNavBarEnabled && currentConfig.getZOrder() < mSystemBarConfigMap.get(
+ RIGHT).getZOrder()) {
+ currentConfig.setPaddingBySide(RIGHT,
+ barVisibilities.get(RIGHT) ? mSystemBarConfigMap.get(RIGHT).getGirth() : 0);
+ }
+ }
+ if (isVerticalBar(side)) {
+ if (mTopNavBarEnabled && currentConfig.getZOrder() < mSystemBarConfigMap.get(
+ TOP).getZOrder()) {
+ currentConfig.setPaddingBySide(TOP,
+ barVisibilities.get(TOP) ? mSystemBarConfigMap.get(TOP).getGirth() : 0);
+ }
+ if (mBottomNavBarEnabled && currentConfig.getZOrder() < mSystemBarConfigMap.get(
+ BOTTOM).getZOrder()) {
+ currentConfig.setPaddingBySide(BOTTOM,
+ barVisibilities.get(BOTTOM) ? mSystemBarConfigMap.get(BOTTOM).getGirth()
+ : 0);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ static int getHunZOrder() {
return HUN_ZORDER;
}
@@ -224,8 +270,14 @@ public class SystemBarConfigs {
}
}
- private void checkSystemBarEnabledForNotificationPanel() throws RuntimeException {
+ private void checkAllOverlappingBarsHaveDifferentZOrders() {
+ checkOverlappingBarsHaveDifferentZOrders(TOP, LEFT);
+ checkOverlappingBarsHaveDifferentZOrders(TOP, RIGHT);
+ checkOverlappingBarsHaveDifferentZOrders(BOTTOM, LEFT);
+ checkOverlappingBarsHaveDifferentZOrders(BOTTOM, RIGHT);
+ }
+ private void checkSystemBarEnabledForNotificationPanel() throws RuntimeException {
String notificationPanelMediatorName =
mResources.getString(R.string.config_notificationPanelViewMediator);
if (notificationPanelMediatorName == null) {
@@ -253,13 +305,72 @@ public class SystemBarConfigs {
}
private void setInsetPaddingsForOverlappingCorners() {
- setInsetPaddingForOverlappingCorner(TOP, LEFT);
- setInsetPaddingForOverlappingCorner(TOP, RIGHT);
- setInsetPaddingForOverlappingCorner(BOTTOM, LEFT);
- setInsetPaddingForOverlappingCorner(BOTTOM, RIGHT);
+ Map<@SystemBarSide Integer, Boolean> systemBarVisibilityOnInit =
+ getSystemBarsVisibilityOnInit();
+ updateInsetPaddings(TOP, systemBarVisibilityOnInit);
+ updateInsetPaddings(BOTTOM, systemBarVisibilityOnInit);
+ updateInsetPaddings(LEFT, systemBarVisibilityOnInit);
+ updateInsetPaddings(RIGHT, systemBarVisibilityOnInit);
}
- private void setInsetPaddingForOverlappingCorner(@SystemBarSide int horizontalSide,
+ private void sortSystemBarSidesByZOrder() {
+ List<SystemBarConfig> systemBarsByZOrder = new ArrayList<>(mSystemBarConfigMap.values());
+
+ systemBarsByZOrder.sort(new Comparator<SystemBarConfig>() {
+ @Override
+ public int compare(SystemBarConfig o1, SystemBarConfig o2) {
+ return o1.getZOrder() - o2.getZOrder();
+ }
+ });
+
+ systemBarsByZOrder.forEach(systemBarConfig -> {
+ mSystemBarSidesByZOrder.add(systemBarConfig.getSide());
+ });
+ }
+
+ @InsetsState.InternalInsetsType
+ private int getSystemBarTypeBySide(@SystemBarSide int side) {
+ return mSystemBarConfigMap.get(side) != null
+ ? mSystemBarConfigMap.get(side).getBarType() : null;
+ }
+
+ // On init, system bars are visible as long as they are enabled.
+ private Map<@SystemBarSide Integer, Boolean> getSystemBarsVisibilityOnInit() {
+ ArrayMap<@SystemBarSide Integer, Boolean> visibilityMap = new ArrayMap<>();
+ visibilityMap.put(TOP, mTopNavBarEnabled);
+ visibilityMap.put(BOTTOM, mBottomNavBarEnabled);
+ visibilityMap.put(LEFT, mLeftNavBarEnabled);
+ visibilityMap.put(RIGHT, mRightNavBarEnabled);
+ return visibilityMap;
+ }
+
+ private Map<@SystemBarSide Integer, Boolean> getSystemBarsVisibility(WindowInsets insets) {
+ ArrayMap<@SystemBarSide Integer, Boolean> visibilityMap = new ArrayMap<>();
+ if (mTopNavBarEnabled) {
+ visibilityMap.put(TOP, getSystemBarInsetVisibleBySide(TOP, insets));
+ }
+ if (mBottomNavBarEnabled) {
+ visibilityMap.put(BOTTOM, getSystemBarInsetVisibleBySide(BOTTOM, insets));
+ }
+ if (mLeftNavBarEnabled) {
+ visibilityMap.put(LEFT, getSystemBarInsetVisibleBySide(LEFT, insets));
+ }
+ if (mRightNavBarEnabled) {
+ visibilityMap.put(RIGHT, getSystemBarInsetVisibleBySide(RIGHT, insets));
+ }
+ return visibilityMap;
+ }
+
+ private boolean getSystemBarInsetVisibleBySide(@SystemBarSide int side, WindowInsets insets) {
+ if (mSystemBarConfigMap.get(side) == null) return false;
+
+ int internalInsetType = BAR_TYPE_MAP[getSystemBarTypeBySide(side)];
+ int publicInsetType = InsetsState.toPublicType(internalInsetType);
+
+ return insets.isVisible(publicInsetType);
+ }
+
+ private void checkOverlappingBarsHaveDifferentZOrders(@SystemBarSide int horizontalSide,
@SystemBarSide int verticalSide) {
if (isVerticalBar(horizontalSide) || isHorizontalBar(verticalSide)) {
@@ -273,15 +384,9 @@ public class SystemBarConfigs {
if (verticalBarConfig != null && horizontalBarConfig != null) {
int horizontalBarZOrder = horizontalBarConfig.getZOrder();
- int horizontalBarGirth = horizontalBarConfig.getGirth();
int verticalBarZOrder = verticalBarConfig.getZOrder();
- int verticalBarGirth = verticalBarConfig.getGirth();
- if (horizontalBarZOrder > verticalBarZOrder) {
- verticalBarConfig.setPaddingBySide(horizontalSide, horizontalBarGirth);
- } else if (horizontalBarZOrder < verticalBarZOrder) {
- horizontalBarConfig.setPaddingBySide(verticalSide, verticalBarGirth);
- } else {
+ if (horizontalBarZOrder == verticalBarZOrder) {
throw new RuntimeException(
BAR_TITLE_MAP.get(horizontalSide) + " " + BAR_TITLE_MAP.get(verticalSide)
+ " have the same Z-Order, and so their placing order cannot be "
@@ -292,21 +397,6 @@ public class SystemBarConfigs {
}
}
- private void sortSystemBarSidesByZOrder() {
- List<SystemBarConfig> systemBarsByZOrder = new ArrayList<>(mSystemBarConfigMap.values());
-
- systemBarsByZOrder.sort(new Comparator<SystemBarConfig>() {
- @Override
- public int compare(SystemBarConfig o1, SystemBarConfig o2) {
- return o1.getZOrder() - o2.getZOrder();
- }
- });
-
- systemBarsByZOrder.forEach(systemBarConfig -> {
- mSystemBarSidesByZOrder.add(systemBarConfig.getSide());
- });
- }
-
private static boolean isHorizontalBar(@SystemBarSide int side) {
return side == TOP || side == BOTTOM;
}
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/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 0b164a2e1a51..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;
@@ -48,6 +49,10 @@ import org.mockito.MockitoAnnotations;
@SmallTest
public class CarNavigationBarControllerTest extends SysuiTestCase {
+ private static final String TOP_NOTIFICATION_PANEL =
+ "com.android.systemui.car.notification.TopNotificationPanelViewMediator";
+ private static final String BOTTOM_NOTIFICATION_PANEL =
+ "com.android.systemui.car.notification.BottomNotificationPanelViewMediator";
private CarNavigationBarController mCarNavigationBar;
private NavigationBarViewFactory mNavigationBarViewFactory;
private TestableResources mTestableResources;
@@ -58,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 {
@@ -73,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()));
}
@@ -117,6 +124,11 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
@Test
public void testGetTopWindow_topDisabled_returnsNull() {
mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, false);
+ mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true);
+ // If Top Notification Panel is used but top navigation bar is not enabled, SystemUI is
+ // expected to crash.
+ mTestableResources.addOverride(R.string.config_notificationPanelViewMediator,
+ BOTTOM_NOTIFICATION_PANEL);
mCarNavigationBar = createNavigationBarController();
ViewGroup window = mCarNavigationBar.getTopWindow();
@@ -148,6 +160,11 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
@Test
public void testGetBottomWindow_bottomDisabled_returnsNull() {
mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, false);
+ mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true);
+ // If Bottom Notification Panel is used but bottom navigation bar is not enabled,
+ // SystemUI is expected to crash.
+ mTestableResources.addOverride(R.string.config_notificationPanelViewMediator,
+ TOP_NOTIFICATION_PANEL);
mCarNavigationBar = createNavigationBarController();
ViewGroup window = mCarNavigationBar.getBottomWindow();
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java
index 8b1589913d1d..072358b9f27c 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java
@@ -25,6 +25,7 @@ import static org.mockito.Mockito.when;
import android.content.res.Resources;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.util.ArrayMap;
import android.view.WindowManager;
import androidx.test.filters.SmallTest;
@@ -41,16 +42,20 @@ import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
public class SystemBarConfigsTest extends SysuiTestCase {
+ private static final int SYSTEM_BAR_GIRTH = 100;
private SystemBarConfigs mSystemBarConfigs;
@Mock
private Resources mResources;
+ @Mock
+ private CarNavigationBarView mCarNavigationBarView;
@Before
public void setUp() {
@@ -133,6 +138,41 @@ public class SystemBarConfigsTest extends SysuiTestCase {
assertEquals(lp.type, WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL);
}
+ @Test
+ public void updateInsetPaddings_overlappingBarWithHigherZOrderDisappeared_removesInset() {
+ mSystemBarConfigs = new SystemBarConfigs(mResources);
+ CarNavigationBarView leftBar = new CarNavigationBarView(mContext, /* attrs= */ null);
+ Map<Integer, Boolean> visibilities = new ArrayMap<>();
+ visibilities.put(SystemBarConfigs.TOP, false);
+ visibilities.put(SystemBarConfigs.BOTTOM, true);
+ visibilities.put(SystemBarConfigs.LEFT, true);
+ visibilities.put(SystemBarConfigs.RIGHT, true);
+
+ mSystemBarConfigs.updateInsetPaddings(SystemBarConfigs.LEFT, visibilities);
+ mSystemBarConfigs.insetSystemBar(SystemBarConfigs.LEFT, leftBar);
+
+ assertEquals(0, leftBar.getPaddingTop());
+ }
+
+ @Test
+ public void updateInsetPaddings_overlappingBarWithHigherZOrderReappeared_addsInset() {
+ mSystemBarConfigs = new SystemBarConfigs(mResources);
+ CarNavigationBarView leftBar = new CarNavigationBarView(mContext, /* attrs= */ null);
+ Map<Integer, Boolean> visibilities = new ArrayMap<>();
+ visibilities.put(SystemBarConfigs.TOP, false);
+ visibilities.put(SystemBarConfigs.BOTTOM, true);
+ visibilities.put(SystemBarConfigs.LEFT, true);
+ visibilities.put(SystemBarConfigs.RIGHT, true);
+
+ mSystemBarConfigs.updateInsetPaddings(SystemBarConfigs.LEFT, visibilities);
+ mSystemBarConfigs.insetSystemBar(SystemBarConfigs.LEFT, leftBar);
+ visibilities.put(SystemBarConfigs.TOP, true);
+ mSystemBarConfigs.updateInsetPaddings(SystemBarConfigs.LEFT, visibilities);
+ mSystemBarConfigs.insetSystemBar(SystemBarConfigs.LEFT, leftBar);
+
+ assertEquals(SYSTEM_BAR_GIRTH, leftBar.getPaddingTop());
+ }
+
// Set valid config where all system bars are enabled.
private void setDefaultValidConfig() {
when(mResources.getBoolean(R.bool.config_enableTopNavigationBar)).thenReturn(true);
@@ -141,13 +181,13 @@ public class SystemBarConfigsTest extends SysuiTestCase {
when(mResources.getBoolean(R.bool.config_enableRightNavigationBar)).thenReturn(true);
when(mResources.getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_height)).thenReturn(100);
+ com.android.internal.R.dimen.status_bar_height)).thenReturn(SYSTEM_BAR_GIRTH);
when(mResources.getDimensionPixelSize(
- com.android.internal.R.dimen.navigation_bar_height)).thenReturn(100);
+ com.android.internal.R.dimen.navigation_bar_height)).thenReturn(SYSTEM_BAR_GIRTH);
when(mResources.getDimensionPixelSize(R.dimen.car_left_navigation_bar_width)).thenReturn(
- 100);
+ SYSTEM_BAR_GIRTH);
when(mResources.getDimensionPixelSize(R.dimen.car_right_navigation_bar_width)).thenReturn(
- 100);
+ SYSTEM_BAR_GIRTH);
when(mResources.getInteger(R.integer.config_topSystemBarType)).thenReturn(0);
when(mResources.getInteger(R.integer.config_bottomSystemBarType)).thenReturn(1);
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/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java
index 2821af97ed98..0d54d7ee9b5c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java
@@ -60,8 +60,30 @@ public class MediaOutputSliceConstants {
"com.android.settings.panel.action.MEDIA_OUTPUT_GROUP";
/**
- * An string extra specifying a media package name.
+ * A string extra specifying a media package name.
*/
public static final String EXTRA_PACKAGE_NAME =
"com.android.settings.panel.extra.PACKAGE_NAME";
+
+ /**
+ * An intent action to launch media output dialog.
+ */
+ public static final String ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG =
+ "com.android.systemui.action.LAUNCH_MEDIA_OUTPUT_DIALOG";
+
+ /**
+ * Settings package name.
+ */
+ public static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
+
+ /**
+ * An intent action to launch Bluetooth paring page.
+ */
+ public static final String ACTION_LAUNCH_BLUETOOTH_PAIRING =
+ "com.android.settings.action.LAUNCH_BLUETOOTH_PAIRING";
+
+ /**
+ * SystemUi package name.
+ */
+ public static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui";
}
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 c0f0aa8bbc8d..708dfd01975a 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,16 @@
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: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,27 +52,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: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/layout/controls_management.xml b/packages/SystemUI/res/layout/controls_management.xml
index ae7f44d19430..b9e711e54b3b 100644
--- a/packages/SystemUI/res/layout/controls_management.xml
+++ b/packages/SystemUI/res/layout/controls_management.xml
@@ -50,7 +50,7 @@
<FrameLayout
android:layout_width="match_parent"
- android:layout_height="72dp">
+ android:layout_height="@dimen/controls_management_footer_height">
<View
android:layout_width="match_parent"
@@ -61,7 +61,8 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:padding="@dimen/controls_management_footer_side_margin">
+ android:paddingHorizontal="@dimen/controls_management_footer_side_margin"
+ android:paddingVertical="@dimen/controls_management_footer_top_margin" >
<Button
android:id="@+id/other_apps"
diff --git a/packages/SystemUI/res/layout/controls_management_favorites.xml b/packages/SystemUI/res/layout/controls_management_favorites.xml
index 4850e7534943..0ddd0e38acb9 100644
--- a/packages/SystemUI/res/layout/controls_management_favorites.xml
+++ b/packages/SystemUI/res/layout/controls_management_favorites.xml
@@ -36,7 +36,7 @@
android:layout_width="wrap_content"
android:layout_height="@dimen/controls_management_page_indicator_height"
android:layout_gravity="center"
- android:layout_marginTop="@dimen/controls_management_list_margin"
+ android:layout_marginTop="@dimen/controls_management_indicator_top_margin"
android:visibility="invisible" />
<androidx.viewpager2.widget.ViewPager2
diff --git a/packages/SystemUI/res/layout/controls_structure_page.xml b/packages/SystemUI/res/layout/controls_structure_page.xml
index f048d62d46d7..412ed566ff1b 100644
--- a/packages/SystemUI/res/layout/controls_structure_page.xml
+++ b/packages/SystemUI/res/layout/controls_structure_page.xml
@@ -21,4 +21,4 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:layout_marginTop="@dimen/controls_management_zone_top_margin"/> \ No newline at end of file
+ android:layout_marginTop="@dimen/controls_management_favorites_top_margin"/> \ No newline at end of file
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-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 9e1b66f07758..b584dfee1e60 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -47,4 +47,15 @@
<dimen name="global_actions_power_dialog_item_height">130dp</dimen>
<dimen name="global_actions_power_dialog_item_bottom_margin">35dp</dimen>
+
+ <dimen name="controls_management_top_padding">12dp</dimen>
+ <dimen name="controls_management_titles_margin">8dp</dimen>
+ <dimen name="controls_management_indicator_top_margin">8dp</dimen>
+ <dimen name="controls_management_list_margin">4dp</dimen>
+ <dimen name="controls_management_footer_height">56dp</dimen>
+ <dimen name="controls_management_zone_top_margin">24dp</dimen>
+
+ <!-- (footer_height -48dp)/2 -->
+ <dimen name="controls_management_footer_top_margin">4dp</dimen>
+ <dimen name="controls_management_favorites_top_margin">8dp</dimen>
</resources>
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/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index d12f0103238d..7b80f00e8333 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1321,15 +1321,19 @@
<dimen name="controls_management_side_padding">16dp</dimen>
<dimen name="controls_management_titles_margin">16dp</dimen>
<dimen name="controls_management_footer_side_margin">8dp</dimen>
+ <dimen name="controls_management_footer_top_margin">@dimen/controls_management_footer_side_margin</dimen>
<dimen name="controls_management_list_margin">16dp</dimen>
+ <dimen name="controls_management_indicator_top_margin">@dimen/controls_management_list_margin</dimen>
<dimen name="controls_management_apps_list_margin">64dp</dimen>
<dimen name="controls_management_editing_list_margin">48dp</dimen>
<dimen name="controls_management_editing_divider_margin">24dp</dimen>
<dimen name="controls_management_apps_extra_side_margin">8dp</dimen>
<dimen name="controls_management_zone_top_margin">32dp</dimen>
+ <dimen name="controls_management_favorites_top_margin">@dimen/controls_management_zone_top_margin</dimen>
<dimen name="controls_management_status_side_margin">16dp</dimen>
<dimen name="controls_management_page_indicator_height">24dp</dimen>
<dimen name="controls_management_checkbox_size">25dp</dimen>
+ <dimen name="controls_management_footer_height">72dp</dimen>
<dimen name="controls_title_size">24sp</dimen>
<dimen name="controls_subtitle_size">16sp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
index 34f721c94ed2..128af3702c49 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
@@ -20,8 +20,13 @@ import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
+import android.graphics.PointF;
import android.provider.Settings;
+import android.util.MathUtils;
import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.widget.ImageView;
@@ -31,7 +36,8 @@ import com.android.systemui.R;
/**
* Shows/hides a {@link android.widget.ImageView} on the screen and changes the values of
* {@link Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE} when the UI is toggled.
- * The button UI would automatically be dismissed after displaying for a period of time.
+ * The button icon is movable by dragging. And the button UI would automatically be dismissed after
+ * displaying for a period of time.
*/
class MagnificationModeSwitch {
@@ -41,6 +47,10 @@ class MagnificationModeSwitch {
private final Context mContext;
private final WindowManager mWindowManager;
private final ImageView mImageView;
+ private final PointF mLastDown = new PointF();
+ private final PointF mLastDrag = new PointF();
+ private final int mTapTimeout = ViewConfiguration.getTapTimeout();
+ private final int mTouchSlop;
private int mMagnificationMode = Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
private final WindowManager.LayoutParams mParams;
private boolean mIsVisible = false;
@@ -56,13 +66,10 @@ class MagnificationModeSwitch {
Context.WINDOW_SERVICE);
mParams = createLayoutParams();
mImageView = imageView;
+ mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
applyResourcesValues();
- mImageView.setOnClickListener(
- view -> {
- removeButton();
- toggleMagnificationMode();
- });
mImageView.setImageResource(getIconResId(mMagnificationMode));
+ mImageView.setOnTouchListener(this::onTouch);
}
private void applyResourcesValues() {
@@ -71,13 +78,59 @@ class MagnificationModeSwitch {
mImageView.setPadding(padding, padding, padding, padding);
}
+ private boolean onTouch(View v, MotionEvent event) {
+ if (!mIsVisible || mImageView == null) {
+ return false;
+ }
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mImageView.setAlpha(1.0f);
+ mImageView.animate().cancel();
+ mLastDown.set(event.getRawX(), event.getRawY());
+ mLastDrag.set(event.getRawX(), event.getRawY());
+ return true;
+ case MotionEvent.ACTION_MOVE:
+ // Move the button position.
+ moveButton(event.getRawX() - mLastDrag.x,
+ event.getRawY() - mLastDrag.y);
+ mLastDrag.set(event.getRawX(), event.getRawY());
+ return true;
+ case MotionEvent.ACTION_UP:
+ // Single tap to toggle magnification mode and the button position will be reset
+ // after the action is performed.
+ final float distance = MathUtils.dist(mLastDown.x, mLastDown.y,
+ event.getRawX(), event.getRawY());
+ if ((event.getEventTime() - event.getDownTime()) <= mTapTimeout
+ && distance <= mTouchSlop) {
+ handleSingleTap();
+ } else {
+ showButton(mMagnificationMode);
+ }
+ return true;
+ case MotionEvent.ACTION_CANCEL:
+ showButton(mMagnificationMode);
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private void moveButton(float offsetX, float offsetY) {
+ mParams.x -= offsetX;
+ mParams.y -= offsetY;
+ mWindowManager.updateViewLayout(mImageView, mParams);
+ }
+
void removeButton() {
if (!mIsVisible) {
return;
}
mImageView.animate().cancel();
mWindowManager.removeView(mImageView);
+ // Reset button status.
mIsVisible = false;
+ mParams.x = 0;
+ mParams.y = 0;
}
void showButton(int mode) {
@@ -120,6 +173,11 @@ class MagnificationModeSwitch {
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, newMode);
}
+ private void handleSingleTap() {
+ removeButton();
+ toggleMagnificationMode();
+ }
+
private static ImageView createView(Context context) {
ImageView imageView = new ImageView(context);
imageView.setClickable(true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
index c023400ca9ca..24e912ed0cc3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
@@ -204,10 +204,8 @@ public class HeadsUpCoordinator implements Coordinator {
public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
NotificationEntry newHUN = mHeadsUpManager.getTopEntry();
if (!Objects.equals(mCurrentHun, newHUN)) {
- endNotifLifetimeExtension();
mCurrentHun = newHUN;
- mNotifPromoter.invalidateList();
- mNotifSectioner.invalidateList();
+ endNotifLifetimeExtension();
}
if (!isHeadsUp) {
mHeadsUpViewBinder.unbindHeadsUpView(entry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java
index 05f5ea85bd4d..f8fe0676e003 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java
@@ -53,8 +53,12 @@ public interface NotifLifetimeExtender {
*/
void cancelLifetimeExtension(NotificationEntry entry);
- /** Callback for notifying the NotifCollection that a lifetime extension has expired. */
+ /** Callback for notifying the NotifCollection that a lifetime extension has expired.*/
interface OnEndLifetimeExtensionCallback {
+ /**
+ * Stop extending the lifetime of `entry` with `extender` and then immediately re-evaluates
+ * whether to continue lifetime extending this notification or to remove it.
+ */
void onEndLifetimeExtension(NotifLifetimeExtender extender, NotificationEntry entry);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 60883f04c9e0..c24d3fcadbf9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -231,8 +231,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
* The algorithm which calculates the properties for our children
*/
private final StackScrollAlgorithm mStackScrollAlgorithm;
-
private final AmbientState mAmbientState;
+
private GroupMembershipManager mGroupMembershipManager;
private GroupExpansionManager mGroupExpansionManager;
private NotificationActivityStarter mNotificationActivityStarter;
@@ -1009,6 +1009,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
return mAmbientState.isPulseExpanding();
}
+ public int getSpeedBumpIndex() {
+ return mAmbientState.getSpeedBumpIndex();
+ }
+
@Override
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
@@ -1063,7 +1067,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@ShadeViewRefactor(RefactorComponent.ADAPTER)
- public void updateSpeedBumpIndex(int newIndex, boolean noAmbient) {
+ private void setSpeedBumpIndex(int newIndex, boolean noAmbient) {
mAmbientState.setSpeedBumpIndex(newIndex);
mNoAmbient = noAmbient;
}
@@ -4992,6 +4996,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mController.updateShowEmptyShadeView();
updateFooter();
}
+
+ updateSpeedBumpIndex();
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -5002,6 +5008,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mController.updateShowEmptyShadeView();
updateFooter();
}
+
+ updateSpeedBumpIndex();
}
public void addContainerViewAt(View v, int index) {
@@ -5011,6 +5019,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mController.updateShowEmptyShadeView();
updateFooter();
}
+
+ updateSpeedBumpIndex();
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -5237,6 +5247,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
protected void setStatusBarState(int statusBarState) {
mStatusBarState = statusBarState;
mAmbientState.setStatusBarState(statusBarState);
+ updateSpeedBumpIndex();
}
void onStatePostChange(boolean fromShadeLocked) {
@@ -5777,7 +5788,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void updateSpeedBumpIndex() {
+ private void updateSpeedBumpIndex() {
int speedBumpIndex = 0;
int currentIndex = 0;
final int N = getChildCount();
@@ -5799,7 +5810,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
}
boolean noAmbient = speedBumpIndex == N;
- updateSpeedBumpIndex(speedBumpIndex, noAmbient);
+ setSpeedBumpIndex(speedBumpIndex, noAmbient);
}
/** Updates the indices of the boundaries between sections. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index a0b49aca6ded..8d792ab6aa58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -1035,10 +1035,6 @@ public class NotificationStackScrollLayoutController {
mView.updateSectionBoundaries(reason);
}
- public void updateSpeedBumpIndex() {
- mView.updateSpeedBumpIndex();
- }
-
public void updateFooter() {
mView.updateFooter();
}
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 169058a3da21..f62783502e5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -3069,7 +3069,6 @@ public class NotificationPanelViewController extends PanelViewController {
*/
public void updateNotificationViews(String reason) {
mNotificationStackScrollLayoutController.updateSectionBoundaries(reason);
- mNotificationStackScrollLayoutController.updateSpeedBumpIndex();
mNotificationStackScrollLayoutController.updateFooter();
mNotificationIconAreaController.updateNotificationIcons(createVisibleEntriesList());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
index ee151c441b68..cdbc647f152b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
@@ -18,6 +18,10 @@ package com.android.systemui.accessibility;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_UP;
import static com.android.systemui.accessibility.MagnificationModeSwitch.getIconResId;
@@ -27,6 +31,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -35,7 +40,9 @@ import android.content.Context;
import android.content.pm.ActivityInfo;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
+import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.ViewPropertyAnimator;
import android.view.WindowManager;
import android.widget.ImageView;
@@ -48,35 +55,38 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class MagnificationModeSwitchTest extends SysuiTestCase {
- @Mock
- private ImageView mMockImageView;
+ private ImageView mSpyImageView;
@Mock
private WindowManager mWindowManager;
@Mock
private ViewPropertyAnimator mViewPropertyAnimator;
private MagnificationModeSwitch mMagnificationModeSwitch;
+ @Captor
+ private ArgumentCaptor<View.OnTouchListener> mTouchListenerCaptor;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ WindowManager wm = mContext.getSystemService(WindowManager.class);
+ doAnswer(invocation ->
+ wm.getMaximumWindowMetrics()
+ ).when(mWindowManager).getMaximumWindowMetrics();
mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
+ mSpyImageView = Mockito.spy(new ImageView(mContext));
+ doAnswer(invocation -> null).when(mSpyImageView).setOnTouchListener(
+ mTouchListenerCaptor.capture());
+ initMockImageViewAndAnimator();
- when(mViewPropertyAnimator.setDuration(anyLong())).thenReturn(mViewPropertyAnimator);
- when(mViewPropertyAnimator.alpha(anyFloat())).thenReturn(mViewPropertyAnimator);
- when(mViewPropertyAnimator.setStartDelay(anyLong())).thenReturn(mViewPropertyAnimator);
- when(mViewPropertyAnimator.withEndAction(any(Runnable.class))).thenReturn(
- mViewPropertyAnimator);
-
- when(mMockImageView.animate()).thenReturn(mViewPropertyAnimator);
-
- mMagnificationModeSwitch = new MagnificationModeSwitch(mContext, mMockImageView);
+ mMagnificationModeSwitch = new MagnificationModeSwitch(mContext, mSpyImageView);
}
@Test
@@ -85,7 +95,7 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
mMagnificationModeSwitch.removeButton();
- verify(mWindowManager).removeView(mMockImageView);
+ verify(mWindowManager).removeView(mSpyImageView);
// First invocation is in showButton.
verify(mViewPropertyAnimator, times(2)).cancel();
}
@@ -94,22 +104,19 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
public void showWindowModeButton_fullscreenMode_addViewAndSetImageResource() {
mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
- verify(mMockImageView).setAlpha(1.0f);
- verify(mMockImageView).setImageResource(
+ verify(mSpyImageView).setAlpha(1.0f);
+ verify(mSpyImageView).setImageResource(
getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW));
- verify(mViewPropertyAnimator).cancel();
- verify(mViewPropertyAnimator).setDuration(anyLong());
- verify(mViewPropertyAnimator).setStartDelay(anyLong());
- verify(mViewPropertyAnimator).alpha(anyFloat());
+ assertShowButtonAnimation();
ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
verify(mViewPropertyAnimator).withEndAction(captor.capture());
- verify(mWindowManager).addView(eq(mMockImageView), any(WindowManager.LayoutParams.class));
+ verify(mWindowManager).addView(eq(mSpyImageView), any(WindowManager.LayoutParams.class));
captor.getValue().run();
// First invocation is in showButton.
verify(mViewPropertyAnimator, times(2)).cancel();
- verify(mWindowManager).removeView(mMockImageView);
+ verify(mWindowManager).removeView(mSpyImageView);
}
@Test
@@ -117,26 +124,131 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
mMagnificationModeSwitch.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
- verify(mMockImageView, times(2)).setImageResource(
+ verify(mSpyImageView, times(2)).setImageResource(
getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN));
}
@Test
- public void performClick_fullscreenMode_removeViewAndChangeSettingsValue() {
- ArgumentCaptor<View.OnClickListener> captor = ArgumentCaptor.forClass(
- View.OnClickListener.class);
- verify(mMockImageView).setOnClickListener(captor.capture());
+ public void performSingleTap_fullscreenMode_removeViewAndChangeSettingsValue() {
mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+ resetMockImageViewAndAnimator();
- captor.getValue().onClick(mMockImageView);
+ // Perform a single-tap
+ final View.OnTouchListener listener = mTouchListenerCaptor.getValue();
+ listener.onTouch(mSpyImageView, MotionEvent.obtain(
+ 0, 0, ACTION_DOWN, 100, 100, 0));
+ verify(mViewPropertyAnimator).cancel();
- // First invocation is in showButton.
- verify(mViewPropertyAnimator, times(2)).cancel();
- verify(mMockImageView).setImageResource(
+ resetMockImageViewAndAnimator();
+ listener.onTouch(mSpyImageView, MotionEvent.obtain(
+ 0, ViewConfiguration.getTapTimeout(), ACTION_UP, 100, 100, 0));
+ verify(mViewPropertyAnimator).cancel();
+ verify(mSpyImageView).setImageResource(
getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW));
- verify(mWindowManager).removeView(mMockImageView);
+ verify(mWindowManager).removeView(mSpyImageView);
final int actualMode = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
assertEquals(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW, actualMode);
}
+
+ @Test
+ public void showMagnificationButton_performDragging_updateViewLayout() {
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+ resetMockImageViewAndAnimator();
+
+ // Perform dragging
+ final View.OnTouchListener listener = mTouchListenerCaptor.getValue();
+ final int offset = ViewConfiguration.get(mContext).getScaledTouchSlop();
+ final int previousMode = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
+ listener.onTouch(mSpyImageView, MotionEvent.obtain(
+ 0, 0, ACTION_DOWN, 100, 100, 0));
+ verify(mSpyImageView).setAlpha(1.0f);
+ verify(mViewPropertyAnimator).cancel();
+
+ listener.onTouch(mSpyImageView, MotionEvent.obtain(
+ 0, ViewConfiguration.getTapTimeout(), ACTION_MOVE, 100 + offset, 100, 0));
+ verify(mWindowManager).updateViewLayout(eq(mSpyImageView),
+ any(WindowManager.LayoutParams.class));
+
+ resetMockImageViewAndAnimator();
+ listener.onTouch(mSpyImageView, MotionEvent.obtain(
+ 0, ViewConfiguration.getTapTimeout() + 10, ACTION_UP, 100 + offset, 100, 0));
+ verify(mSpyImageView).setAlpha(1.0f);
+ assertModeUnchanged(previousMode);
+ assertShowButtonAnimation();
+ }
+
+ @Test
+ public void performSingleTapActionCanceled_showButtonAnimation() {
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+ resetMockImageViewAndAnimator();
+
+ // Perform single tap
+ final View.OnTouchListener listener = mTouchListenerCaptor.getValue();
+ final int previousMode = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
+ listener.onTouch(mSpyImageView, MotionEvent.obtain(
+ 0, 0, ACTION_DOWN, 100, 100, 0));
+
+ resetMockImageViewAndAnimator();
+ listener.onTouch(mSpyImageView, MotionEvent.obtain(
+ 0, ViewConfiguration.getTapTimeout(), ACTION_CANCEL, 100, 100, 0));
+ verify(mSpyImageView).setAlpha(1.0f);
+ assertModeUnchanged(previousMode);
+ assertShowButtonAnimation();
+ }
+
+ @Test
+ public void performDraggingActionCanceled_showButtonAnimation() {
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+ resetMockImageViewAndAnimator();
+
+ // Perform dragging
+ final View.OnTouchListener listener = mTouchListenerCaptor.getValue();
+ final int offset = ViewConfiguration.get(mContext).getScaledTouchSlop();
+ final int previousMode = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
+ listener.onTouch(mSpyImageView, MotionEvent.obtain(
+ 0, 0, ACTION_DOWN, 100, 100, 0));
+ listener.onTouch(mSpyImageView, MotionEvent.obtain(
+ 0, ViewConfiguration.getTapTimeout(), ACTION_MOVE, 100 + offset, 100, 0));
+
+ resetMockImageViewAndAnimator();
+ listener.onTouch(mSpyImageView, MotionEvent.obtain(
+ 0, ViewConfiguration.getTapTimeout(), ACTION_CANCEL, 100 + offset, 100, 0));
+ verify(mSpyImageView).setAlpha(1.0f);
+ assertModeUnchanged(previousMode);
+ assertShowButtonAnimation();
+ }
+
+ private void assertModeUnchanged(int expectedMode) {
+ final int actualMode = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
+ assertEquals(expectedMode, actualMode);
+ }
+
+ private void assertShowButtonAnimation() {
+ verify(mViewPropertyAnimator).cancel();
+ verify(mViewPropertyAnimator).setDuration(anyLong());
+ verify(mViewPropertyAnimator).setStartDelay(anyLong());
+ verify(mViewPropertyAnimator).alpha(anyFloat());
+ verify(mViewPropertyAnimator).start();
+ }
+
+ private void initMockImageViewAndAnimator() {
+ when(mViewPropertyAnimator.setDuration(anyLong())).thenReturn(mViewPropertyAnimator);
+ when(mViewPropertyAnimator.alpha(anyFloat())).thenReturn(mViewPropertyAnimator);
+ when(mViewPropertyAnimator.setStartDelay(anyLong())).thenReturn(mViewPropertyAnimator);
+ when(mViewPropertyAnimator.withEndAction(any(Runnable.class))).thenReturn(
+ mViewPropertyAnimator);
+
+ when(mSpyImageView.animate()).thenReturn(mViewPropertyAnimator);
+ }
+
+ private void resetMockImageViewAndAnimator() {
+ Mockito.reset(mViewPropertyAnimator);
+ Mockito.reset(mSpyImageView);
+ initMockImageViewAndAnimator();
+ }
}
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/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 5264458cb9cd..f48e6ea7941e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -449,6 +449,60 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
.DISMISS_SILENT_NOTIFICATIONS_PANEL.getId(), mUiEventLoggerFake.eventId(0));
}
+ @Test
+ public void testAddNotificationUpdatesSpeedBumpIndex() {
+ // initial state == -1
+ assertEquals(-1, mStackScroller.getSpeedBumpIndex());
+
+ // add notification that's before the speed bump
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+ NotificationEntry entry = mock(NotificationEntry.class);
+ when(row.getEntry()).thenReturn(entry);
+ when(entry.isAmbient()).thenReturn(false);
+ mStackScroller.addContainerView(row);
+
+ // speed bump = 1
+ assertEquals(1, mStackScroller.getSpeedBumpIndex());
+ }
+
+ @Test
+ public void testAddAmbientNotificationNoSpeedBumpUpdate() {
+ // initial state == -1
+ assertEquals(-1, mStackScroller.getSpeedBumpIndex());
+
+ // add notification that's after the speed bump
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+ NotificationEntry entry = mock(NotificationEntry.class);
+ when(row.getEntry()).thenReturn(entry);
+ when(entry.isAmbient()).thenReturn(true);
+ mStackScroller.addContainerView(row);
+
+ // speed bump is set to 0
+ assertEquals(0, mStackScroller.getSpeedBumpIndex());
+ }
+
+ @Test
+ public void testRemoveNotificationUpdatesSpeedBump() {
+ // initial state == -1
+ assertEquals(-1, mStackScroller.getSpeedBumpIndex());
+
+ // add 3 notification that are after the speed bump
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+ NotificationEntry entry = mock(NotificationEntry.class);
+ when(row.getEntry()).thenReturn(entry);
+ when(entry.isAmbient()).thenReturn(false);
+ mStackScroller.addContainerView(row);
+
+ // speed bump is 1
+ assertEquals(1, mStackScroller.getSpeedBumpIndex());
+
+ // remove the notification that was before the speed bump
+ mStackScroller.removeContainerView(row);
+
+ // speed bump is now 0
+ assertEquals(0, mStackScroller.getSpeedBumpIndex());
+ }
+
private void setBarStateForTest(int state) {
// Can't inject this through the listener or we end up on the actual implementation
// rather than the mock because the spy just coppied the anonymous inner /shruggie.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java
index 8cb5f3e65a5e..69764227040b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/settings/FakeSettings.java
@@ -53,9 +53,9 @@ public class FakeSettings implements SecureSettings, GlobalSettings, SystemSetti
}
@Override
- public void registerContentObserverForUser(String name, ContentObserver settingsObserver,
- int userHandle) {
- SettingsKey key = new SettingsKey(userHandle, name);
+ public void registerContentObserverForUser(Uri uri, boolean notifyDescendents,
+ ContentObserver settingsObserver, int userHandle) {
+ SettingsKey key = new SettingsKey(userHandle, uri.toString());
mContentObservers.putIfAbsent(key, new ArrayList<>());
List<ContentObserver> observers = mContentObservers.get(key);
observers.add(settingsObserver);
@@ -86,7 +86,7 @@ public class FakeSettings implements SecureSettings, GlobalSettings, SystemSetti
@Override
public String getStringForUser(String name, int userHandle) {
- return mValues.get(new SettingsKey(userHandle, name));
+ return mValues.get(new SettingsKey(userHandle, getUriFor(name).toString()));
}
@Override
@@ -107,7 +107,7 @@ public class FakeSettings implements SecureSettings, GlobalSettings, SystemSetti
@Override
public boolean putStringForUser(String name, String value, String tag, boolean makeDefault,
int userHandle, boolean overrideableByRestore) {
- SettingsKey key = new SettingsKey(userHandle, name);
+ SettingsKey key = new SettingsKey(userHandle, getUriFor(name).toString());
mValues.put(key, value);
Uri uri = getUriFor(name);
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index eb38f5199ce5..f56b0b5578f7 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -612,8 +612,8 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
}
}
- private AtomicFile getStorageFileForUser(int uid) {
- return mUidToStorage.computeIfAbsent(uid, (u) ->
+ private AtomicFile getStorageFileForUser(int userId) {
+ return mUidToStorage.computeIfAbsent(userId, (u) ->
new AtomicFile(new File(
//TODO deprecated method - what's the right replacement?
Environment.getUserSystemDirectory(u),
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index dbdcc8729eea..bcb7bfacfaf3 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -489,7 +489,7 @@ final class UiModeManagerService extends SystemService {
* @return True if the new value is different from the old value. False otherwise.
*/
private boolean updateNightModeFromSettingsLocked(Context context, Resources res, int userId) {
- if (mCarModeEnabled) {
+ if (mCarModeEnabled || mCar) {
return false;
}
int oldNightMode = mNightMode;
@@ -1036,7 +1036,7 @@ final class UiModeManagerService extends SystemService {
private void persistNightMode(int user) {
// Only persist setting if not in car mode
- if (mCarModeEnabled) return;
+ if (mCarModeEnabled || mCar) return;
Secure.putIntForUser(getContext().getContentResolver(),
Secure.UI_NIGHT_MODE, mNightMode, user);
Secure.putLongForUser(getContext().getContentResolver(),
@@ -1049,7 +1049,7 @@ final class UiModeManagerService extends SystemService {
private void persistNightModeOverrides(int user) {
// Only persist setting if not in car mode
- if (mCarModeEnabled) return;
+ if (mCarModeEnabled || mCar) return;
Secure.putIntForUser(getContext().getContentResolver(),
Secure.UI_NIGHT_MODE_OVERRIDE_ON, mOverrideNightModeOn ? 1 : 0, user);
Secure.putIntForUser(getContext().getContentResolver(),
@@ -1100,7 +1100,7 @@ final class UiModeManagerService extends SystemService {
}
// Override night mode in power save mode if not in car mode
- if (mPowerSave && !mCarModeEnabled) {
+ if (mPowerSave && !mCarModeEnabled && !mCar) {
uiMode &= ~Configuration.UI_MODE_NIGHT_NO;
uiMode |= Configuration.UI_MODE_NIGHT_YES;
} else {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 44258d1a69e8..b15273a2bd70 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2103,17 +2103,13 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
try {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(false);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
"meminfo", pw)) return;
PriorityDump.dump(mPriorityDumper, fd, pw, args);
} finally {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(true);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
}
}
}
@@ -2127,17 +2123,13 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
try {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(false);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
"gfxinfo", pw)) return;
mActivityManagerService.dumpGraphicsHardwareUsage(fd, pw, args);
} finally {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(true);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
}
}
}
@@ -2151,17 +2143,13 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
try {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(false);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
"dbinfo", pw)) return;
mActivityManagerService.dumpDbInfo(fd, pw, args);
} finally {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(true);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
}
}
}
@@ -2207,9 +2195,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
try {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(false);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
"cacheinfo", pw)) {
@@ -2218,9 +2204,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mActivityManagerService.dumpBinderCacheContents(fd, pw, args);
} finally {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(true);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
}
}
}
@@ -16834,14 +16818,14 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- Process.enableFreezer(false);
+ mOomAdjuster.mCachedAppOptimizer.enableFreezer(false);
final RemoteCallback intermediateCallback = new RemoteCallback(
new RemoteCallback.OnResultListener() {
@Override
public void onResult(Bundle result) {
finishCallback.sendResult(result);
- Process.enableFreezer(true);
+ mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
}
}, null);
@@ -18771,4 +18755,16 @@ public class ActivityManagerService extends IActivityManager.Stub
mAppErrors.resetStateLocked();
}
}
+
+ @Override
+ public boolean enableAppFreezer(boolean enable) {
+ int callerUid = Binder.getCallingUid();
+
+ // Only system can toggle the freezer state
+ if (callerUid == SYSTEM_UID) {
+ return mOomAdjuster.mCachedAppOptimizer.enableFreezer(enable);
+ } else {
+ throw new SecurityException("Caller uid " + callerUid + " cannot set freezer state ");
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index d9fde0f6728a..c5047e5eed03 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -208,6 +208,8 @@ public final class CachedAppOptimizer {
@GuardedBy("mPhenotypeFlagLock")
private volatile boolean mUseCompaction = DEFAULT_USE_COMPACTION;
private volatile boolean mUseFreezer = DEFAULT_USE_FREEZER;
+ @GuardedBy("this")
+ private int mFreezerDisableCount = 1; // Freezer is initially disabled, until enabled
private final Random mRandom = new Random();
@GuardedBy("mPhenotypeFlagLock")
@VisibleForTesting volatile float mCompactStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE;
@@ -420,25 +422,82 @@ public final class CachedAppOptimizer {
}
/**
- * Determines whether the freezer is correctly supported by this system
+ * Enables or disabled the app freezer.
+ * @param enable Enables the freezer if true, disables it if false.
+ * @return true if the operation completed successfully, false otherwise.
+ */
+ public synchronized boolean enableFreezer(boolean enable) {
+ if (!mUseFreezer) {
+ return false;
+ }
+
+ if (enable) {
+ mFreezerDisableCount--;
+
+ if (mFreezerDisableCount > 0) {
+ return true;
+ } else if (mFreezerDisableCount < 0) {
+ Slog.e(TAG_AM, "unbalanced call to enableFreezer, ignoring");
+ mFreezerDisableCount = 0;
+ return false;
+ }
+ } else {
+ mFreezerDisableCount++;
+
+ if (mFreezerDisableCount > 1) {
+ return true;
+ }
+ }
+
+ try {
+ enableFreezerInternal(enable);
+ return true;
+ } catch (java.lang.RuntimeException e) {
+ if (enable) {
+ mFreezerDisableCount = 0;
+ } else {
+ mFreezerDisableCount = 1;
+ }
+
+ Slog.e(TAG_AM, "Exception handling freezer state (enable: " + enable + "): "
+ + e.toString());
+ }
+
+ return false;
+ }
+
+ /**
+ * Enable or disable the freezer. When enable == false all frozen processes are unfrozen,
+ * but aren't removed from the freezer. While in this state, processes can be added or removed
+ * by using Process.setProcessFrozen(), but they wouldn't be actually frozen until the freezer
+ * is enabled. If enable == true all processes in the freezer are frozen.
+ *
+ * @param enable Specify whether to enable (true) or disable (false) the freezer.
+ *
+ * @hide
+ */
+ private static native void enableFreezerInternal(boolean enable);
+
+ /**
+ * Determines whether the freezer is supported by this system
*/
public static boolean isFreezerSupported() {
boolean supported = false;
FileReader fr = null;
try {
- fr = new FileReader("/dev/freezer/frozen/freezer.killable");
- int i = fr.read();
+ fr = new FileReader("/sys/fs/cgroup/freezer/cgroup.freeze");
+ char state = (char) fr.read();
- if ((char) i == '1') {
+ if (state == '1' || state == '0') {
supported = true;
} else {
- Slog.w(TAG_AM, "Freezer killability is turned off, disabling freezer");
+ Slog.e(TAG_AM, "unexpected value in cgroup.freeze");
}
} catch (java.io.FileNotFoundException e) {
- Slog.d(TAG_AM, "Freezer.killable not present, disabling freezer");
+ Slog.d(TAG_AM, "cgroup.freeze not present");
} catch (Exception e) {
- Slog.d(TAG_AM, "Unable to read freezer.killable, disabling freezer: " + e.toString());
+ Slog.d(TAG_AM, "unable to read cgroup.freeze: " + e.toString());
}
if (fr != null) {
@@ -471,6 +530,8 @@ public final class CachedAppOptimizer {
if (mUseFreezer && mFreezeHandler == null) {
Slog.d(TAG_AM, "Freezer enabled");
+ enableFreezer(true);
+
if (!mCachedAppOptimizerThread.isAlive()) {
mCachedAppOptimizerThread.start();
}
@@ -479,6 +540,8 @@ public final class CachedAppOptimizer {
Process.setThreadGroupAndCpuset(mCachedAppOptimizerThread.getThreadId(),
Process.THREAD_GROUP_SYSTEM);
+ } else {
+ enableFreezer(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/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 9128359250df..4be596de3af1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -195,6 +195,8 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
if (listener != null) {
listener.onAuthenticationFailed(getSensorId());
}
+ } else {
+ mAlreadyDone = true;
}
}
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java
index dec40e39fb29..e585b48d49b6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java
@@ -176,6 +176,11 @@ public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinde
// TODO(b/157790417): Move this to the scheduler
void binderDiedInternal(boolean clearListener) {
+ if (isAlreadyDone()) {
+ Slog.w(TAG, "Binder died but client is finished, ignoring");
+ return;
+ }
+
// If the current client dies we should cancel the current operation.
if (this instanceof Interruptable) {
Slog.e(TAG, "Binder died, cancelling client");
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 7c8fb5aefd1e..1f0066a43538 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -29,6 +29,7 @@ import static android.net.SocketKeepalive.ERROR_INVALID_INTERVAL;
import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
import static android.net.SocketKeepalive.ERROR_INVALID_NETWORK;
import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
+import static android.net.SocketKeepalive.ERROR_STOP_REASON_UNINITIALIZED;
import static android.net.SocketKeepalive.ERROR_UNSUPPORTED;
import static android.net.SocketKeepalive.MAX_INTERVAL_SEC;
import static android.net.SocketKeepalive.MIN_INTERVAL_SEC;
@@ -152,6 +153,7 @@ public class KeepaliveTracker {
private static final int STARTED = 3;
private static final int STOPPING = 4;
private int mStartedState = NOT_STARTED;
+ private int mStopReason = ERROR_STOP_REASON_UNINITIALIZED;
KeepaliveInfo(@NonNull ISocketKeepaliveCallback callback,
@NonNull NetworkAgentInfo nai,
@@ -365,6 +367,11 @@ public class KeepaliveTracker {
Log.e(TAG, "Cannot stop unowned keepalive " + mSlot + " on " + mNai.network);
}
}
+ // Store the reason of stopping, and report it after the keepalive is fully stopped.
+ if (mStopReason != ERROR_STOP_REASON_UNINITIALIZED) {
+ throw new IllegalStateException("Unexpected stop reason: " + mStopReason);
+ }
+ mStopReason = reason;
Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.toShortString()
+ ": " + reason);
switch (mStartedState) {
@@ -403,24 +410,6 @@ public class KeepaliveTracker {
Log.wtf(TAG, "Error closing fd for keepalive " + mSlot + ": " + e);
}
}
-
- if (reason == SUCCESS) {
- try {
- mCallback.onStopped();
- } catch (RemoteException e) {
- Log.w(TAG, "Discarded onStop callback: " + reason);
- }
- } else if (reason == DATA_RECEIVED) {
- try {
- mCallback.onDataReceived();
- } catch (RemoteException e) {
- Log.w(TAG, "Discarded onDataReceived callback: " + reason);
- }
- } else {
- notifyErrorCallback(mCallback, reason);
- }
-
- unlinkDeathRecipient();
}
void onFileDescriptorInitiatedStop(final int socketKeepaliveReason) {
@@ -505,12 +494,37 @@ public class KeepaliveTracker {
Log.e(TAG, "Attempt to remove nonexistent keepalive " + slot + " on " + networkName);
return;
}
+
+ // Remove the keepalive from hash table so the slot can be considered available when reusing
+ // it.
networkKeepalives.remove(slot);
Log.d(TAG, "Remove keepalive " + slot + " on " + networkName + ", "
+ networkKeepalives.size() + " remains.");
if (networkKeepalives.isEmpty()) {
mKeepalives.remove(nai);
}
+
+ // Notify app that the keepalive is stopped.
+ final int reason = ki.mStopReason;
+ if (reason == SUCCESS) {
+ try {
+ ki.mCallback.onStopped();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Discarded onStop callback: " + reason);
+ }
+ } else if (reason == DATA_RECEIVED) {
+ try {
+ ki.mCallback.onDataReceived();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Discarded onDataReceived callback: " + reason);
+ }
+ } else if (reason == ERROR_STOP_REASON_UNINITIALIZED) {
+ throw new IllegalStateException("Unexpected stop reason: " + reason);
+ } else {
+ notifyErrorCallback(ki.mCallback, reason);
+ }
+
+ ki.unlinkDeathRecipient();
}
public void handleCheckKeepalivesStillValid(NetworkAgentInfo nai) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 0576e91b79eb..70ffaae1a9af 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1970,7 +1970,21 @@ public class HdmiControlService extends SystemService {
@Override
public void powerOnRemoteDevice(int logicalAddress, int powerStatus) {
- // TODO(amyjojo): implement the method
+ enforceAccessPermission();
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ Slog.i(TAG, "Device "
+ + logicalAddress + " power status is " + powerStatus
+ + " before power on command sent out");
+ if (getSwitchDevice() != null) {
+ getSwitchDevice().sendUserControlPressedAndReleased(
+ logicalAddress, HdmiCecKeycode.CEC_KEYCODE_POWER_ON_FUNCTION);
+ } else {
+ Slog.e(TAG, "Can't get the correct local device to handle routing.");
+ }
+ }
+ });
}
@Override
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/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b6b7e9321b16..c6269eba8120 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -14530,11 +14530,13 @@ public class PackageManagerService extends IPackageManager.Stub
Log.v(TAG, "restoreAndPostInstall userId=" + userId + " package=" + res.pkg);
}
- // A restore should be requested at this point if (a) the install
- // succeeded, (b) the operation is not an update.
+ // A restore should be performed at this point if (a) the install
+ // succeeded, (b) the operation is not an update, and (c) the new
+ // package has not opted out of backup participation.
final boolean update = res.removedInfo != null
&& res.removedInfo.removedPackage != null;
- boolean doRestore = !update;
+ boolean allowBackup = res.pkg != null && res.pkg.isAllowBackup();
+ boolean doRestore = !update && allowBackup;
// Set up the post-install work request bookkeeping. This will be used
// and cleaned up by the post-install event handling regardless of whether
@@ -21645,8 +21647,6 @@ public class PackageManagerService extends IPackageManager.Stub
.getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_ALL);
co.onChange(true);
- mAppsFilter.onSystemReady();
-
// Disable any carrier apps. We do this very early in boot to prevent the apps from being
// disabled after already being started.
CarrierAppUtils.disableCarrierAppsUntilPrivileged(
@@ -21795,6 +21795,9 @@ public class PackageManagerService extends IPackageManager.Stub
mInstallerService.restoreAndApplyStagedSessionIfNeeded();
mExistingPackages = null;
+
+ // We'll do this last as it builds its cache while holding mLock via callback.
+ mAppsFilter.onSystemReady();
}
public void waitForAppDataPrepared() {
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 75a88e2e04b6..f7721a4d6f22 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -414,17 +414,14 @@ public final class DefaultPermissionGrantPolicy {
if (pkg == null
|| !doesPackageSupportRuntimePermissions(pkg)
|| ArrayUtils.isEmpty(pkg.requestedPermissions)
- || !pkg.applicationInfo.isPrivilegedApp()) {
+ || !pm.isGranted(Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ pkg, UserHandle.of(userId))) {
continue;
}
- for (String permission : pkg.requestedPermissions) {
- if (Manifest.permission.READ_PRIVILEGED_PHONE_STATE.equals(permission)) {
- grantRuntimePermissions(pm, pkg,
- Collections.singleton(Manifest.permission.READ_PHONE_STATE),
- true, // systemFixed
- userId);
- }
- }
+ grantRuntimePermissions(pm, pkg,
+ Collections.singleton(Manifest.permission.READ_PHONE_STATE),
+ true, // systemFixed
+ userId);
}
}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
index 8e5ecee8262b..ebe9733e5d55 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
@@ -35,7 +35,8 @@ import java.util.TimerTask;
* HAL whenever they expire.
*/
public class SoundTriggerHw2Watchdog implements ISoundTriggerHw2 {
- private static final long TIMEOUT_MS = 1000;
+ // TODO(b/166328980): Reduce this to 1000 as soon as HAL is fixed.
+ private static final long TIMEOUT_MS = 10000;
private static final String TAG = "SoundTriggerHw2Watchdog";
private final @NonNull
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
index c382e1152e4b..5a587cc9764c 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
@@ -36,7 +36,6 @@ import android.media.soundtrigger_middleware.Status;
import android.os.IBinder;
import android.os.IHwBinder;
import android.os.RemoteException;
-import android.os.ServiceSpecificException;
import android.util.Log;
import java.util.ArrayList;
@@ -293,7 +292,11 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient {
} catch (Exception e) {
// We must do this outside the lock, to avoid possible deadlocks with the remote
// process that provides the audio sessions, which may also be calling into us.
- mAudioSessionProvider.releaseSession(audioSession.mSessionHandle);
+ try {
+ mAudioSessionProvider.releaseSession(audioSession.mSessionHandle);
+ } catch (Exception ee) {
+ Log.e(TAG, "Failed to release session.", ee);
+ }
throw e;
}
}
@@ -321,7 +324,11 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient {
} catch (Exception e) {
// We must do this outside the lock, to avoid possible deadlocks with the remote
// process that provides the audio sessions, which may also be calling into us.
- mAudioSessionProvider.releaseSession(audioSession.mSessionHandle);
+ try {
+ mAudioSessionProvider.releaseSession(audioSession.mSessionHandle);
+ } catch (Exception ee) {
+ Log.e(TAG, "Failed to release session.", ee);
+ }
throw e;
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 7d4d5629dacd..aea0a58c9acb 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2122,11 +2122,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return task != null ? task.getRootTaskId() : INVALID_TASK_ID;
}
- DisplayContent getDisplay() {
- final Task stack = getRootTask();
- return stack != null ? stack.getDisplay() : null;
- }
-
@Override
@Nullable
TaskDisplayArea getDisplayArea() {
@@ -2386,7 +2381,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- return (canReceiveKeys() || isAlwaysFocusable()) && getDisplay() != null;
+ // Check isAttached() because the method may be called when removing this activity from
+ // display, and WindowContainer#compareTo will throw exception if it doesn't have a parent
+ // when updating focused window from DisplayContent#findFocusedWindow.
+ return (canReceiveKeys() || isAlwaysFocusable()) && isAttached();
}
/**
@@ -2663,7 +2661,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
private void prepareActivityHideTransitionAnimation(int transit) {
- final DisplayContent dc = getDisplay().mDisplayContent;
+ final DisplayContent dc = mDisplayContent;
dc.prepareAppTransition(transit, false);
setVisibility(false);
dc.executeAppTransition();
@@ -2708,7 +2706,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
if (ensureVisibility) {
- getDisplay().ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
+ mDisplayContent.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
false /* preserveWindows */, true /* notifyClients */);
}
}
@@ -4652,7 +4650,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
// Check if the activity is on a sleeping display, and if it can turn it ON.
- if (getDisplay().isSleeping()) {
+ if (mDisplayContent.isSleeping()) {
final boolean canTurnScreenOn = !mSetToSleep || canTurnScreenOn()
|| canShowWhenLocked() || containsDismissKeyguardWindow();
if (!canTurnScreenOn) {
@@ -4931,12 +4929,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
r.setSavedState(null /* savedState */);
- final DisplayContent display = r.getDisplay();
- if (display != null) {
- display.handleActivitySizeCompatModeIfNeeded(r);
- }
-
- r.getDisplayContent().mUnknownAppVisibilityController.notifyAppResumedFinished(r);
+ r.mDisplayContent.handleActivitySizeCompatModeIfNeeded(r);
+ r.mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(r);
}
/**
@@ -6834,7 +6828,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
onMergedOverrideConfigurationChanged();
}
- final DisplayContent display = getDisplay();
+ final DisplayContent display = mDisplayContent;
if (display == null) {
return;
}
@@ -7259,7 +7253,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(
- getDisplay().mDisplayContent.isNextTransitionForward());
+ mDisplayContent.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
@@ -7584,11 +7578,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* otherwise.
*/
boolean isFocusedActivityOnDisplay() {
- final DisplayContent display = getDisplay();
- if (display == null) {
- return false;
- }
- return display.forAllTaskDisplayAreas(taskDisplayArea ->
+ return mDisplayContent.forAllTaskDisplayAreas(taskDisplayArea ->
taskDisplayArea.getFocusedActivity() == this);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 34f7f79d7716..9df192b76f9a 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -837,7 +837,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.appToken);
- final DisplayContent dc = r.getDisplay().mDisplayContent;
+ final DisplayContent dc = r.mDisplayContent;
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index f206259b8fe0..19755f29043e 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1731,7 +1731,7 @@ class ActivityStarter {
0 /* configChanges */, !PRESERVE_WINDOWS);
// Go ahead and tell window manager to execute app transition for this activity
// since the app transition will not be triggered through the resume channel.
- mTargetStack.getDisplay().mDisplayContent.executeAppTransition();
+ mTargetStack.mDisplayContent.executeAppTransition();
} else {
// If the target stack was not previously focusable (previous top running activity
// on that stack was not visible) then any prior calls to move the stack to the
@@ -2481,7 +2481,7 @@ class ActivityStarter {
// to the front if the caller is not itself in the front.
final boolean differentTopTask;
if (mTargetStack.getDisplayArea() == mPreferredTaskDisplayArea) {
- final Task focusStack = mTargetStack.getDisplay().getFocusedStack();
+ final Task focusStack = mTargetStack.mDisplayContent.getFocusedStack();
final ActivityRecord curTop = (focusStack == null)
? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
final Task topTask = curTop != null ? curTop.getTask() : null;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index c58b5b50d508..505233cd8a4a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2025,7 +2025,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (self.isState(
Task.ActivityState.RESUMED, Task.ActivityState.PAUSING)) {
- self.getDisplay().mDisplayContent.mAppTransition.overridePendingAppTransition(
+ self.mDisplayContent.mAppTransition.overridePendingAppTransition(
packageName, enterAnim, exitAnim, null, null);
}
@@ -2409,7 +2409,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
} else {
stack.setWindowingMode(windowingMode);
- stack.getDisplay().ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
+ stack.mDisplayContent.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
true /* notifyClients */);
}
return true;
@@ -4176,7 +4176,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (params.hasSetAspectRatio()
&& !mWindowManager.isValidPictureInPictureAspectRatio(
- r.getDisplay(), params.getAspectRatio())) {
+ r.mDisplayContent, params.getAspectRatio())) {
final float minAspectRatio = mContext.getResources().getFloat(
com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
final float maxAspectRatio = mContext.getResources().getFloat(
@@ -4620,7 +4620,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
final long origId = Binder.clearCallingIdentity();
try {
- display.mDisplayContent.registerRemoteAnimations(definition);
+ display.registerRemoteAnimations(definition);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -5466,7 +5466,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
updateResumedAppTrace(r);
mLastResumedActivity = r;
- final boolean changed = r.getDisplay().setFocusedApp(r);
+ final boolean changed = r.mDisplayContent.setFocusedApp(r);
if (changed) {
mWindowManager.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
true /*updateInputWindows*/);
@@ -6206,12 +6206,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// We might change the visibilities here, so prepare an empty app transition which
// might be overridden later if we actually change visibilities.
- final DisplayContent displayContent =
- mRootWindowContainer.getDisplayContent(displayId);
- if (displayContent == null) {
+ final DisplayContent dc = mRootWindowContainer.getDisplayContent(displayId);
+ if (dc == null) {
return;
}
- final DisplayContent dc = displayContent.mDisplayContent;
final boolean wasTransitionSet =
dc.mAppTransition.getAppTransition() != TRANSIT_NONE;
if (!wasTransitionSet) {
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index c36a75b01293..69e8c57a489c 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -190,7 +190,7 @@ class KeyguardController {
mAodShowing ? 1 : 0,
1 /* keyguardGoingAway */,
"keyguardGoingAway");
- mRootWindowContainer.getDefaultDisplay().mDisplayContent
+ mRootWindowContainer.getDefaultDisplay()
.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
false /* alwaysKeepCurrent */, convertTransitFlags(flags),
false /* forceOverride */);
@@ -314,7 +314,7 @@ class KeyguardController {
if (isKeyguardLocked()) {
mService.deferWindowLayout();
try {
- mRootWindowContainer.getDefaultDisplay().mDisplayContent
+ mRootWindowContainer.getDefaultDisplay()
.prepareAppTransition(resolveOccludeTransit(),
false /* alwaysKeepCurrent */, 0 /* flags */,
true /* forceOverride */);
@@ -344,8 +344,7 @@ class KeyguardController {
// If we are about to unocclude the Keyguard, but we can dismiss it without security,
// we immediately dismiss the Keyguard so the activity gets shown without a flicker.
- final DisplayContent dc =
- mRootWindowContainer.getDefaultDisplay().mDisplayContent;
+ final DisplayContent dc = mRootWindowContainer.getDefaultDisplay();
if (mKeyguardShowing && canDismissKeyguard()
&& dc.mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
dc.prepareAppTransition(mBeforeUnoccludeTransit, false /* alwaysKeepCurrent */,
@@ -368,7 +367,7 @@ class KeyguardController {
}
private int resolveOccludeTransit() {
- final DisplayContent dc = mRootWindowContainer.getDefaultDisplay().mDisplayContent;
+ final DisplayContent dc = mRootWindowContainer.getDefaultDisplay();
if (mBeforeUnoccludeTransit != TRANSIT_UNSET
&& dc.mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
// TODO(b/113840485): Handle app transition for individual display.
@@ -485,7 +484,7 @@ class KeyguardController {
}
// TODO(b/123372519): isShowingDream can only works on default display.
if (mDisplayId == DEFAULT_DISPLAY) {
- mOccluded |= mService.mRootWindowContainer.getDefaultDisplay().mDisplayContent
+ mOccluded |= mService.mRootWindowContainer.getDefaultDisplay()
.getDisplayPolicy().isShowingDreamLw();
}
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index c8d7693c9229..c49690157c08 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -619,7 +619,7 @@ public class LockTaskController {
mSupervisor.mRootWindowContainer.resumeFocusedStacksTopActivities();
final Task rootTask = task.getRootTask();
if (rootTask != null) {
- rootTask.getDisplay().mDisplayContent.executeAppTransition();
+ rootTask.mDisplayContent.executeAppTransition();
}
} else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
mSupervisor.handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED,
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 3c64ffb237d6..255b3f147d30 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1346,11 +1346,8 @@ class RecentTasks {
// singleTaskInstance is set on the VirtualDisplay managed by ActivityView
// TODO(b/126185105): Find a different signal to use besides isSingleTaskInstance
final Task rootTask = task.getRootTask();
- if (rootTask != null) {
- DisplayContent display = rootTask.getDisplay();
- if (display != null && display.isSingleTaskInstance()) {
- return false;
- }
+ if (rootTask != null && rootTask.isSingleTaskInstance()) {
+ return false;
}
// If we're in lock task mode, ignore the root task
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 6182a55b6e52..6539e1325ec1 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -40,6 +40,7 @@ import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
+
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_ON;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
@@ -89,6 +90,7 @@ import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREEN
import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;
import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_ACTION_PENDING;
+
import static java.lang.Integer.MAX_VALUE;
import android.annotation.IntDef;
@@ -2746,7 +2748,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
r.detachFromProcess();
- r.getDisplay().mDisplayContent.prepareAppTransition(
+ r.mDisplayContent.prepareAppTransition(
TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
r.destroyIfPossible("handleAppCrashed");
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index bfaaf462ed51..5606eb676b1d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2319,8 +2319,7 @@ class Task extends WindowContainer<WindowContainer> {
taskDisplayArea.onStackWindowingModeChanged(this);
}
- final DisplayContent display = getDisplay();
- if (display == null ) {
+ if (mDisplayContent == null) {
return;
}
@@ -2336,7 +2335,7 @@ class Task extends WindowContainer<WindowContainer> {
final int newRotation = getWindowConfiguration().getRotation();
final boolean rotationChanged = prevRotation != newRotation;
if (rotationChanged) {
- display.mDisplayContent.rotateBounds(
+ mDisplayContent.rotateBounds(
newParentConfig.windowConfiguration.getBounds(), prevRotation, newRotation,
newBounds);
hasNewOverrideBounds = true;
@@ -2594,15 +2593,12 @@ class Task extends WindowContainer<WindowContainer> {
outNonDecorBounds.set(bounds);
outStableBounds.set(bounds);
final Task rootTask = getRootTask();
- if (rootTask == null || rootTask.getDisplay() == null) {
- return;
- }
- DisplayPolicy policy = rootTask.getDisplay().mDisplayContent.getDisplayPolicy();
- if (policy == null) {
+ if (rootTask == null || rootTask.mDisplayContent == null) {
return;
}
mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
+ final DisplayPolicy policy = rootTask.mDisplayContent.getDisplayPolicy();
policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets);
intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);
@@ -2990,14 +2986,6 @@ class Task extends WindowContainer<WindowContainer> {
}
}
- @Override
- DisplayContent getDisplayContent() {
- // TODO: Why aren't we just using our own display content vs. parent's???
- final Task stack = getRootTask();
- return stack != null && stack != this
- ? stack.getDisplayContent() : super.getDisplayContent();
- }
-
int getDisplayId() {
final DisplayContent dc = getDisplayContent();
return dc != null ? dc.mDisplayId : INVALID_DISPLAY;
@@ -5173,14 +5161,9 @@ class Task extends WindowContainer<WindowContainer> {
!PRESERVE_WINDOWS);
}
- DisplayContent getDisplay() {
- return getDisplayContent();
- }
-
/** @return true if the stack can only contain one task */
boolean isSingleTaskInstance() {
- final DisplayContent display = getDisplay();
- return display != null && display.isSingleTaskInstance();
+ return mDisplayContent != null && mDisplayContent.isSingleTaskInstance();
}
final boolean isHomeOrRecentsStack() {
@@ -5620,8 +5603,7 @@ class Task extends WindowContainer<WindowContainer> {
* otherwise.
*/
boolean isFocusedStackOnDisplay() {
- final DisplayContent display = getDisplay();
- return display != null && this == display.getFocusedStack();
+ return mDisplayContent != null && this == mDisplayContent.getFocusedStack();
}
/**
@@ -5760,7 +5742,7 @@ class Task extends WindowContainer<WindowContainer> {
* {@link Display#FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD} applied.
*/
boolean canShowWithInsecureKeyguard() {
- final DisplayContent displayContent = getDisplay();
+ final DisplayContent displayContent = mDisplayContent;
if (displayContent == null) {
throw new IllegalStateException("Stack is not attached to any display, stackId="
+ getRootTaskId());
@@ -6399,7 +6381,7 @@ class Task extends WindowContainer<WindowContainer> {
// The transition animation and starting window are not needed if {@code allowMoveToFront}
// is false, because the activity won't be visible.
if ((!isHomeOrRecentsStack() || hasActivity()) && allowMoveToFront) {
- final DisplayContent dc = getDisplay().mDisplayContent;
+ final DisplayContent dc = mDisplayContent;
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare open transition: starting " + r);
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
@@ -6410,7 +6392,7 @@ class Task extends WindowContainer<WindowContainer> {
if (newTask) {
if (r.mLaunchTaskBehind) {
transit = TRANSIT_TASK_OPEN_BEHIND;
- } else if (getDisplay().isSingleTaskInstance()) {
+ } else if (dc.isSingleTaskInstance()) {
// If a new task is being launched in a single task display, we don't need
// to play normal animation, but need to trigger a callback when an app
// transition is actually handled. So ignore already prepared activity, and
@@ -6454,7 +6436,7 @@ class Task extends WindowContainer<WindowContainer> {
ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
// Go ahead to execute app transition for this activity since the app transition
// will not be triggered through the resume channel.
- getDisplay().mDisplayContent.executeAppTransition();
+ mDisplayContent.executeAppTransition();
} else if (SHOW_APP_STARTING_PREVIEW && doShow) {
// Figure out if we are transitioning from another activity that is
// "has the same starting icon" as the next one. This allows the
@@ -6567,7 +6549,7 @@ class Task extends WindowContainer<WindowContainer> {
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
Task finishedTask = r.getTask();
- getDisplay().mDisplayContent.prepareAppTransition(
+ mDisplayContent.prepareAppTransition(
TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
r.finishIfPossible(reason, false /* oomAdj */);
@@ -6807,7 +6789,7 @@ class Task extends WindowContainer<WindowContainer> {
ActivityOptions.abort(options);
}
}
- getDisplay().mDisplayContent.prepareAppTransition(transit, false,
+ mDisplayContent.prepareAppTransition(transit, false,
0 /* flags */, forceOverride);
}
@@ -6855,7 +6837,7 @@ class Task extends WindowContainer<WindowContainer> {
// Defer updating the IME target since the new IME target will try to get computed
// before updating all closing and opening apps, which can cause the ime target to
// get calculated incorrectly.
- getDisplay().deferUpdateImeTarget();
+ mDisplayContent.deferUpdateImeTarget();
// Shift all activities with this task up to the top
// of the stack, keeping them in the same internal order.
@@ -6879,7 +6861,7 @@ class Task extends WindowContainer<WindowContainer> {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr);
if (noAnimation) {
- getDisplay().mDisplayContent.prepareAppTransition(TRANSIT_NONE, false);
+ mDisplayContent.prepareAppTransition(TRANSIT_NONE, false /* alwaysKeepCurrent */);
if (r != null) {
mStackSupervisor.mNoAnimActivities.add(r);
}
@@ -6909,7 +6891,7 @@ class Task extends WindowContainer<WindowContainer> {
mAtmService.getTaskChangeNotificationController()
.notifyTaskMovedToFront(tr.getTaskInfo());
} finally {
- getDisplay().continueUpdateImeTarget();
+ mDisplayContent.continueUpdateImeTarget();
}
}
@@ -6959,7 +6941,7 @@ class Task extends WindowContainer<WindowContainer> {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to back transition: task="
+ tr.mTaskId);
- getDisplay().mDisplayContent.prepareAppTransition(TRANSIT_TASK_TO_BACK, false);
+ mDisplayContent.prepareAppTransition(TRANSIT_TASK_TO_BACK, false /* alwaysKeepCurrent */);
moveToBack("moveTaskToBackLocked", tr);
if (inPinnedWindowingMode()) {
@@ -6968,7 +6950,7 @@ class Task extends WindowContainer<WindowContainer> {
}
mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */,
- getDisplay().mDisplayId, false /* markFrozenIfConfigChanged */,
+ mDisplayContent.mDisplayId, false /* markFrozenIfConfigChanged */,
false /* deferResume */);
ActivityRecord topActivity = getDisplayArea().topRunningActivity();
@@ -6976,7 +6958,7 @@ class Task extends WindowContainer<WindowContainer> {
if (topStack != null && topStack != this && topActivity.isState(RESUMED)) {
// Usually resuming a top activity triggers the next app transition, but nothing's got
// resumed in this case, so we need to execute it explicitly.
- getDisplay().mDisplayContent.executeAppTransition();
+ mDisplayContent.executeAppTransition();
} else {
mRootWindowContainer.resumeFocusedStacksTopActivities();
}
@@ -7575,12 +7557,12 @@ class Task extends WindowContainer<WindowContainer> {
}
void executeAppTransition(ActivityOptions options) {
- getDisplay().mDisplayContent.executeAppTransition();
+ mDisplayContent.executeAppTransition();
ActivityOptions.abort(options);
}
boolean shouldSleepActivities() {
- final DisplayContent display = getDisplay();
+ final DisplayContent display = mDisplayContent;
// Do not sleep activities in this stack if we're marked as focused and the keyguard
// is in the process of going away.
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index c5ebace78261..8bf0820c7dad 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -729,15 +729,16 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
return true;
}
- final DisplayContent display = activity.getDisplay();
- if (display == null) {
+ if (!activity.isAttached()) {
// No need to update if the activity hasn't attach to any display.
return false;
}
boolean canUpdate = false;
final DisplayContent topDisplay =
- mPreQTopResumedActivity != null ? mPreQTopResumedActivity.getDisplay() : null;
+ (mPreQTopResumedActivity != null && mPreQTopResumedActivity.isAttached())
+ ? mPreQTopResumedActivity.mDisplayContent
+ : null;
// Update the topmost activity if current top activity is
// - not on any display OR
// - no longer visible OR
@@ -748,8 +749,9 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
canUpdate = true;
}
+ final DisplayContent display = activity.mDisplayContent;
// Update the topmost activity if the current top activity wasn't on top of the other one.
- if (!canUpdate && topDisplay.mDisplayContent.compareTo(display.mDisplayContent) < 0) {
+ if (!canUpdate && topDisplay.compareTo(display) < 0) {
canUpdate = true;
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 4b5f38c40e4f..d84f9d1a7dad 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -97,6 +97,7 @@ cc_defaults {
"libnativehelper",
"libnativewindow",
"libpowermanager",
+ "libprocessgroup",
"libutils",
"libui",
"libvibratorservice",
diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
index 6a6da0e2b395..7e9e11d209a6 100644
--- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
+++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
@@ -30,6 +30,7 @@
#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
#include <jni.h>
+#include <processgroup/processgroup.h>
using android::base::StringPrintf;
using android::base::WriteStringToFile;
@@ -74,9 +75,26 @@ static void com_android_server_am_CachedAppOptimizer_compactSystem(JNIEnv *, job
}
}
+static void com_android_server_am_CachedAppOptimizer_enableFreezerInternal(
+ JNIEnv *env, jobject clazz, jboolean enable) {
+ bool success = true;
+
+ if (enable) {
+ success = SetTaskProfiles(0, {"FreezerEnabled"}, true);
+ } else {
+ success = SetTaskProfiles(0, {"FreezerDisabled"}, true);
+ }
+
+ if (!success) {
+ jniThrowException(env, "java/lang/RuntimeException", "Unknown error");
+ }
+}
+
static const JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"compactSystem", "()V", (void*)com_android_server_am_CachedAppOptimizer_compactSystem},
+ {"enableFreezerInternal", "(Z)V",
+ (void*)com_android_server_am_CachedAppOptimizer_enableFreezerInternal},
};
int register_android_server_am_CachedAppOptimizer(JNIEnv* env)
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/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/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 59f0a7987bda..bca990c659ae 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -415,12 +415,12 @@ public class ActivityRecordTests extends WindowTestsBase {
public void ignoreRequestedOrientationInFreeformWindows() {
mStack.setWindowingMode(WINDOWING_MODE_FREEFORM);
final Rect stableRect = new Rect();
- mStack.getDisplay().mDisplayContent.getStableRect(stableRect);
+ mStack.mDisplayContent.getStableRect(stableRect);
// Carve out non-decor insets from stableRect
final Rect insets = new Rect();
- final DisplayInfo displayInfo = mStack.getDisplay().getDisplayInfo();
- final DisplayPolicy policy = mStack.getDisplay().getDisplayPolicy();
+ final DisplayInfo displayInfo = mStack.mDisplayContent.getDisplayInfo();
+ final DisplayPolicy policy = mStack.mDisplayContent.getDisplayPolicy();
policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
displayInfo.logicalHeight, displayInfo.displayCutout, insets);
policy.convertNonDecorInsetsToStableInsets(insets, displayInfo.rotation);
@@ -454,12 +454,12 @@ public class ActivityRecordTests extends WindowTestsBase {
public void ignoreRequestedOrientationInSplitWindows() {
mStack.setWindowingMode(WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
final Rect stableRect = new Rect();
- mStack.getDisplay().getStableRect(stableRect);
+ mStack.mDisplayContent.getStableRect(stableRect);
// Carve out non-decor insets from stableRect
final Rect insets = new Rect();
- final DisplayInfo displayInfo = mStack.getDisplay().getDisplayInfo();
- final DisplayPolicy policy = mStack.getDisplay().getDisplayPolicy();
+ final DisplayInfo displayInfo = mStack.mDisplayContent.getDisplayInfo();
+ final DisplayPolicy policy = mStack.mDisplayContent.getDisplayPolicy();
policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
displayInfo.logicalHeight, displayInfo.displayCutout, insets);
policy.convertNonDecorInsetsToStableInsets(insets, displayInfo.rotation);
@@ -844,7 +844,7 @@ public class ActivityRecordTests extends WindowTestsBase {
FINISH_RESULT_REQUESTED, mActivity.finishIfPossible("test", false /* oomAdj */));
assertEquals(PAUSING, mActivity.getState());
verify(mActivity).setVisibility(eq(false));
- verify(mActivity.getDisplay().mDisplayContent)
+ verify(mActivity.mDisplayContent)
.prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
}
@@ -888,9 +888,9 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.finishIfPossible("test", false /* oomAdj */);
verify(mActivity).setVisibility(eq(false));
- verify(mActivity.getDisplay().mDisplayContent)
+ verify(mActivity.mDisplayContent)
.prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
- verify(mActivity.getDisplay().mDisplayContent, never()).executeAppTransition();
+ verify(mActivity.mDisplayContent, never()).executeAppTransition();
}
/**
@@ -904,9 +904,9 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.finishIfPossible("test", false /* oomAdj */);
verify(mActivity, atLeast(1)).setVisibility(eq(false));
- verify(mActivity.getDisplay().mDisplayContent)
+ verify(mActivity.mDisplayContent)
.prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
- verify(mActivity.getDisplay().mDisplayContent).executeAppTransition();
+ verify(mActivity.mDisplayContent).executeAppTransition();
}
/**
@@ -922,7 +922,7 @@ public class ActivityRecordTests extends WindowTestsBase {
mActivity.finishIfPossible("test", false /* oomAdj */);
- verify(mActivity.getDisplay().mDisplayContent, never())
+ verify(mActivity.mDisplayContent, never())
.prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
}
@@ -1166,7 +1166,7 @@ public class ActivityRecordTests extends WindowTestsBase {
// Finish the second activity
secondActivity.finishing = true;
secondActivity.completeFinishing("test");
- verify(secondActivity.getDisplay()).ensureActivitiesVisible(null /* starting */,
+ verify(secondActivity.mDisplayContent).ensureActivitiesVisible(null /* starting */,
0 /* configChanges */ , false /* preserveWindows */,
true /* notifyClients */);
@@ -1174,7 +1174,7 @@ public class ActivityRecordTests extends WindowTestsBase {
firstActivity.finishing = true;
firstActivity.mVisibleRequested = true;
firstActivity.completeFinishing("test");
- verify(firstActivity.getDisplay(), times(2)).ensureActivitiesVisible(null /* starting */,
+ verify(firstActivity.mDisplayContent, times(2)).ensureActivitiesVisible(null /* starting */,
0 /* configChanges */ , false /* preserveWindows */,
true /* notifyClients */);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 4cad39762a7b..524f32deb864 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -1432,7 +1432,7 @@ public class ActivityStackTests extends WindowTestsBase {
final KeyguardController keyguardController = mSupervisor.getKeyguardController();
display.isDefaultDisplay = isDefaultDisplay;
- doReturn(display).when(mStack).getDisplay();
+ mStack.mDisplayContent = display;
doReturn(keyguardGoingAway).when(keyguardController).isKeyguardGoingAway();
doReturn(displaySleeping).when(display).isSleeping();
doReturn(focusedStack).when(mStack).isFocusedStackOnDisplay();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index e5c9ecc7676d..e537b7c204cc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -890,7 +890,7 @@ public class ActivityStarterTests extends WindowTestsBase {
.execute();
// Ensure the activity is moved to secondary display.
- assertEquals(secondaryDisplay, topActivity.getDisplay());
+ assertEquals(secondaryDisplay, topActivity.mDisplayContent);
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 982e469cba92..6c648a894821 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -90,7 +90,7 @@ public class SizeCompatTests extends WindowTestsBase {
prepareUnresizable(1.5f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
final Rect originalOverrideBounds = new Rect(mActivity.getBounds());
- resizeDisplay(mStack.getDisplay(), 600, 1200);
+ resizeDisplay(mStack.mDisplayContent, 600, 1200);
// The visible activity should recompute configuration according to the last parent bounds.
mAtm.restartActivityProcessIfVisible(mActivity.appToken);
@@ -218,7 +218,7 @@ public class SizeCompatTests extends WindowTestsBase {
final Rect currentBounds = mActivity.getWindowConfiguration().getBounds();
// Change the size of current display.
- resizeDisplay(mStack.getDisplay(), 1000, 2000);
+ resizeDisplay(mStack.mDisplayContent, 1000, 2000);
assertEquals(origBounds.width(), currentBounds.width());
assertEquals(origBounds.height(), currentBounds.height());
@@ -229,7 +229,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertEquals(mActivity.getBounds().top, currentBounds.top);
// Change display size to a different orientation
- resizeDisplay(mStack.getDisplay(), 2000, 1000);
+ resizeDisplay(mStack.mDisplayContent, 2000, 1000);
assertEquals(origBounds.width(), currentBounds.width());
assertEquals(origBounds.height(), currentBounds.height());
}
@@ -412,7 +412,7 @@ public class SizeCompatTests extends WindowTestsBase {
public void testResetNonVisibleActivity() {
setUpDisplaySizeWithApp(1000, 2500);
prepareUnresizable(1.5f, SCREEN_ORIENTATION_UNSPECIFIED);
- final DisplayContent display = mStack.getDisplay();
+ final DisplayContent display = mStack.mDisplayContent;
// Resize the display so the activity is in size compatibility mode.
resizeDisplay(display, 900, 1800);
@@ -464,7 +464,7 @@ public class SizeCompatTests extends WindowTestsBase {
});
// Resize the display so that the activity exercises size-compat mode.
- resizeDisplay(mStack.getDisplay(), 1000, 2500);
+ resizeDisplay(mStack.mDisplayContent, 1000, 2500);
// Expect the exact token when the activity is in size compatibility mode.
assertEquals(1, compatTokens.size());
@@ -477,7 +477,7 @@ public class SizeCompatTests extends WindowTestsBase {
activity.restartProcessIfVisible();
// The full lifecycle isn't hooked up so manually set state to resumed
activity.setState(Task.ActivityState.RESUMED, "testHandleActivitySizeCompatMode");
- mStack.getDisplay().handleActivitySizeCompatModeIfNeeded(activity);
+ mStack.mDisplayContent.handleActivitySizeCompatModeIfNeeded(activity);
// Expect null token when switching to non-size-compat mode activity.
assertEquals(1, compatTokens.size());
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index bcb5c992f162..1f23bf38c2f2 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -218,7 +218,6 @@ import android.util.Log;
import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -4028,7 +4027,6 @@ public class ConnectivityServiceTest {
}
@Test
- @FlakyTest(bugId = 140305589)
public void testPacketKeepalives() throws Exception {
InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
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;
diff --git a/wifi/api/current.txt b/wifi/api/current.txt
index ee7320f9a5ef..b104decab73c 100644
--- a/wifi/api/current.txt
+++ b/wifi/api/current.txt
@@ -507,6 +507,7 @@ package android.net.wifi {
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setBssid(@NonNull android.net.MacAddress);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setCredentialSharedWithUser(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsAppInteractionRequired(boolean);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsEnhancedMacRandomizationEnabled(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsEnhancedOpen(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsHiddenSsid(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsInitialAutojoinEnabled(boolean);
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index a3c4ae764612..e4e900ffe12a 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -149,6 +149,11 @@ public final class WifiNetworkSuggestion implements Parcelable {
*/
private boolean mIsNetworkUntrusted;
+ /**
+ * Whether this network will use enhanced MAC randomization.
+ */
+ private boolean mIsEnhancedMacRandomizationEnabled;
+
public Builder() {
mSsid = null;
mBssid = null;
@@ -171,6 +176,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
mWapiEnterpriseConfig = null;
mIsNetworkUntrusted = false;
mPriorityGroup = 0;
+ mIsEnhancedMacRandomizationEnabled = true;
}
/**
@@ -394,6 +400,29 @@ public final class WifiNetworkSuggestion implements Parcelable {
}
/**
+ * Specifies the MAC randomization method.
+ * <p>
+ * Suggested networks will never use the device (factory) MAC address to associate to the
+ * network - instead they use a locally generated random MAC address. This method controls
+ * the strategy for generating the random MAC address:
+ * <li> Persisted MAC randomization (false): generates the MAC address from a secret seed
+ * and information from the Wi-Fi configuration (SSID or Passpoint profile). That means that
+ * the same generated MAC address will be used for each subsequent association. </li>
+ * <li> Enhanced MAC randomization (true - the default): periodically generates a new MAC
+ * address new connections. Under this option, the randomized MAC address should change
+ * if the suggestion is removed and then added back. </li>
+ *
+ * @param enabled {@code true} to periodically change the randomized MAC address.
+ * {@code false} to use the same randomized MAC for all connections to this
+ * network.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setIsEnhancedMacRandomizationEnabled(boolean enabled) {
+ mIsEnhancedMacRandomizationEnabled = enabled;
+ return this;
+ }
+
+ /**
* Specifies whether the app needs to log in to a captive portal to obtain Internet access.
* <p>
* This will dictate if the directed broadcast
@@ -577,6 +606,9 @@ public final class WifiNetworkSuggestion implements Parcelable {
wifiConfiguration.meteredOverride = mMeteredOverride;
wifiConfiguration.carrierId = mCarrierId;
wifiConfiguration.trusted = !mIsNetworkUntrusted;
+ wifiConfiguration.macRandomizationSetting = mIsEnhancedMacRandomizationEnabled
+ ? WifiConfiguration.RANDOMIZATION_ENHANCED
+ : WifiConfiguration.RANDOMIZATION_PERSISTENT;
return wifiConfiguration;
}
@@ -607,6 +639,9 @@ public final class WifiNetworkSuggestion implements Parcelable {
wifiConfiguration.trusted = !mIsNetworkUntrusted;
mPasspointConfiguration.setCarrierId(mCarrierId);
mPasspointConfiguration.setMeteredOverride(wifiConfiguration.meteredOverride);
+ wifiConfiguration.macRandomizationSetting = mIsEnhancedMacRandomizationEnabled
+ ? WifiConfiguration.RANDOMIZATION_ENHANCED
+ : WifiConfiguration.RANDOMIZATION_PERSISTENT;
return wifiConfiguration;
}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index 3744a5183793..7d5a45216fc4 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -610,6 +610,33 @@ public class WifiNetworkSuggestionTest {
}
/**
+ * Verify that the macRandomizationSetting defaults to RANDOMIZATION_ENHANCED and could be set
+ * to RANDOMIZATION_PERSISTENT.
+ */
+ @Test
+ public void testWifiNetworkSuggestionBuilderSetMacRandomization() {
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .build();
+ assertEquals(WifiConfiguration.RANDOMIZATION_ENHANCED,
+ suggestion.wifiConfiguration.macRandomizationSetting);
+
+ suggestion = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setIsEnhancedMacRandomizationEnabled(false)
+ .build();
+ assertEquals(WifiConfiguration.RANDOMIZATION_PERSISTENT,
+ suggestion.wifiConfiguration.macRandomizationSetting);
+
+ suggestion = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setIsEnhancedMacRandomizationEnabled(true)
+ .build();
+ assertEquals(WifiConfiguration.RANDOMIZATION_ENHANCED,
+ suggestion.wifiConfiguration.macRandomizationSetting);
+ }
+
+ /**
* Check that parcel marshalling/unmarshalling works
*/
@Test