Merge "Don't use the internal module name"
diff --git a/api/current.txt b/api/current.txt
index e5baa7c..a1629f1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -31665,6 +31665,7 @@
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 0a47248..cd9e02d 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -695,4 +695,14 @@
* 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/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index b7c3289..e6ea044 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2512,12 +2512,16 @@
}
/**
- * If {@link SessionParams#setInstallAsInstantApp(boolean)} was called with {@code true},
- * return true. If it was called with {@code false} or if it was not called return false.
+ * Get if this session is to be installed as Instant Apps.
*
- * @hide
+ * @param isInstantApp an unused parameter and is ignored.
+ * @return {@code true} if {@link SessionParams#setInstallAsInstantApp(boolean)} was called
+ * with {@code true}; {@code false} if it was called with {@code false} or if it was not
+ * called.
*
* @see #getInstallAsFullApp
+ *
+ * @hide
*/
@SystemApi
public boolean getInstallAsInstantApp(boolean isInstantApp) {
@@ -2525,12 +2529,16 @@
}
/**
- * If {@link SessionParams#setInstallAsInstantApp(boolean)} was called with {@code false},
- * return true. If it was called with {@code true} or if it was not called return false.
+ * Get if this session is to be installed as full apps.
*
- * @hide
+ * @param isInstantApp an unused parameter and is ignored.
+ * @return {@code true} if {@link SessionParams#setInstallAsInstantApp(boolean)} was called
+ * with {@code false}; {code false} if it was called with {@code true} or if it was not
+ * called.
*
* @see #getInstallAsInstantApp
+ *
+ * @hide
*/
@SystemApi
public boolean getInstallAsFullApp(boolean isInstantApp) {
diff --git a/core/java/android/net/SocketKeepalive.java b/core/java/android/net/SocketKeepalive.java
index 46aef10..a7dce18 100644
--- a/core/java/android/net/SocketKeepalive.java
+++ b/core/java/android/net/SocketKeepalive.java
@@ -85,6 +85,12 @@
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 683993f..0185ba4 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -18,6 +18,7 @@
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 @@
// 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 @@
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 a4077fb..efea953 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -947,7 +947,7 @@
/**
* 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/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 35605c4..796654a4d 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -54,6 +54,7 @@
import android.view.ViewDebug;
import android.view.ViewHierarchyEncoder;
import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
@@ -314,9 +315,6 @@
setMax(a.getInt(R.styleable.ProgressBar_max, mMax));
setProgress(a.getInt(R.styleable.ProgressBar_progress, mProgress));
- // onProgressRefresh() is only called when the progress changes. So we should set
- // stateDescription during initialization here.
- super.setStateDescription(formatStateDescription(mProgress));
setSecondaryProgress(a.getInt(
R.styleable.ProgressBar_secondaryProgress, mSecondaryProgress));
@@ -1627,7 +1625,8 @@
}
void onProgressRefresh(float scale, boolean fromUser, int progress) {
- if (mCustomStateDescription == null) {
+ if (AccessibilityManager.getInstance(mContext).isEnabled()
+ && mCustomStateDescription == null) {
super.setStateDescription(formatStateDescription(mProgress));
}
}
@@ -2351,6 +2350,7 @@
AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_INT, getMin(), getMax(),
getProgress());
info.setRangeInfo(rangeInfo);
+ info.setStateDescription(formatStateDescription(mProgress));
}
}
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index cbcbe7f..c51f334 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -372,22 +372,6 @@
}
}
-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 @@
{"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 586b26e..cbce38e 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 @@
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 @@
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 @@
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 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 @@
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 @@
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 e8465c2..be03353 100644
--- a/core/jni/android_view_KeyCharacterMap.h
+++ b/core/jni/android_view_KeyCharacterMap.h
@@ -25,7 +25,7 @@
/* 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/jni/Android.bp b/media/jni/Android.bp
index 7518496..1e9cf2c 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -166,26 +166,3 @@
],
}
-cc_library_shared {
- name: "libmediatranscodemanager_jni",
- srcs: [
- "android_media_MediaTranscodeManager.cpp",
- ],
-
- shared_libs: [
- "libandroid_runtime",
- "libcutils",
- "liblog",
- "libmedia",
- ],
-
- export_include_dirs: ["."],
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wno-error=deprecated-declarations",
- "-Wunused",
- "-Wunreachable-code",
- ],
-}
diff --git a/media/jni/android_media_MediaTranscodeManager.cpp b/media/jni/android_media_MediaTranscodeManager.cpp
deleted file mode 100644
index 6695f85..0000000
--- a/media/jni/android_media_MediaTranscodeManager.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaTranscodeManager_JNI"
-
-#include "android_runtime/AndroidRuntime.h"
-#include "jni.h"
-
-#include <nativehelper/JNIHelp.h>
-#include <utils/Log.h>
-
-namespace {
-
-// NOTE: Keep these enums in sync with their equivalents in MediaTranscodeManager.java.
-enum {
- ID_INVALID = -1
-};
-
-enum {
- EVENT_JOB_STARTED = 1,
- EVENT_JOB_PROGRESSED = 2,
- EVENT_JOB_FINISHED = 3,
-};
-
-enum {
- RESULT_NONE = 1,
- RESULT_SUCCESS = 2,
- RESULT_ERROR = 3,
- RESULT_CANCELED = 4,
-};
-
-struct {
- jmethodID postEventFromNative;
-} gMediaTranscodeManagerClassInfo;
-
-using namespace android;
-
-void android_media_MediaTranscodeManager_native_init(JNIEnv *env, jclass clazz) {
- ALOGV("android_media_MediaTranscodeManager_native_init");
-
- gMediaTranscodeManagerClassInfo.postEventFromNative = env->GetMethodID(
- clazz, "postEventFromNative", "(IJI)V");
- LOG_ALWAYS_FATAL_IF(gMediaTranscodeManagerClassInfo.postEventFromNative == NULL,
- "can't find android/media/MediaTranscodeManager.postEventFromNative");
-}
-
-jlong android_media_MediaTranscodeManager_requestUniqueJobID(
- JNIEnv *env __unused, jobject thiz __unused) {
- ALOGV("android_media_MediaTranscodeManager_reserveUniqueJobID");
- static std::atomic_int32_t sJobIDCounter{0};
- jlong id = (jlong)++sJobIDCounter;
- return id;
-}
-
-jboolean android_media_MediaTranscodeManager_enqueueTranscodingRequest(
- JNIEnv *env, jobject thiz, jlong id, jobject request, jobject context __unused) {
- ALOGV("android_media_MediaTranscodeManager_enqueueTranscodingRequest");
- if (!request) {
- return ID_INVALID;
- }
-
- env->CallVoidMethod(thiz, gMediaTranscodeManagerClassInfo.postEventFromNative,
- EVENT_JOB_FINISHED, id, RESULT_ERROR);
- return true;
-}
-
-void android_media_MediaTranscodeManager_cancelTranscodingRequest(
- JNIEnv *env __unused, jobject thiz __unused, jlong jobID __unused) {
- ALOGV("android_media_MediaTranscodeManager_cancelTranscodingRequest");
-}
-
-const JNINativeMethod gMethods[] = {
- { "native_init", "()V",
- (void *)android_media_MediaTranscodeManager_native_init },
- { "native_requestUniqueJobID", "()J",
- (void *)android_media_MediaTranscodeManager_requestUniqueJobID },
- { "native_enqueueTranscodingRequest",
- "(JLandroid/media/MediaTranscodeManager$TranscodingRequest;Landroid/content/Context;)Z",
- (void *)android_media_MediaTranscodeManager_enqueueTranscodingRequest },
- { "native_cancelTranscodingRequest", "(J)V",
- (void *)android_media_MediaTranscodeManager_cancelTranscodingRequest },
-};
-
-} // namespace anonymous
-
-int register_android_media_MediaTranscodeManager(JNIEnv *env) {
- return AndroidRuntime::registerNativeMethods(env,
- "android/media/MediaTranscodeManager", gMethods, NELEM(gMethods));
-}
-
-jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
-{
- JNIEnv* env = NULL;
- jint result = -1;
-
- if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
- ALOGE("ERROR: GetEnv failed\n");
- return result;
- }
- assert(env != NULL);
-
- if (register_android_media_MediaTranscodeManager(env) < 0) {
- ALOGE("ERROR: MediaTranscodeManager native registration failed");
- goto bail;
- }
-
- /* success -- return valid version number */
- result = JNI_VERSION_1_4;
-
-bail:
- return result;
-}
diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java
index 04909ef..73e1d98 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 @@
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 @@
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 @@
String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
transcode(testVideoName, transcodedVideoName);
- }*/
+ }
@Test
public void testBenchmarkingAVCToAVCWith361FramesWithoutAudio() throws Exception {
@@ -194,16 +191,14 @@
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 @@
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 @@
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 @@
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 @@
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 a8d8a2f..e028a0e 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 2a4e91a..9504e61 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 0000000..c78f0ed
--- /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 0000000..16192df
--- /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 bdc44b3..55c968e 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 0000000..817b714
--- /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 9d9ad0f..aabf916 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 0000000..1195d05
--- /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 0000000..469ac91
--- /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 0000000..a3fca22
--- /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 546b1a8..71fcc53 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 0000000..d197409
--- /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 a49a637..b07dde5 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"/>
+ 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_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/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_width="wrap_content"
android:layout_height="match_parent"
- android:layout_weight="1"/>
+ 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.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_height="match_parent"
- android:layout_weight="1"/>
-
- <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_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>
+ <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 cdc29eec..af8482a8 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 9634950..d9c1491 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 ab94265..1e15aff 100644
--- a/packages/CarSystemUI/res/values/colors.xml
+++ b/packages/CarSystemUI/res/values/colors.xml
@@ -31,6 +31,9 @@
<color name="docked_divider_background">@*android:color/car_grey_50</color>
<color name="system_bar_background_opaque">#ff172026</color>
+ <!-- colors for status bar -->
+ <color name="system_bar_user_icon_color">#ffffff</color>
+ <color name="system_bar_text_color">#ffffff</color>
<color name="status_bar_background_color">#33000000</color>
<drawable name="system_bar_background">@color/status_bar_background_color</drawable>
diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml
index d3277de..1fe2760 100644
--- a/packages/CarSystemUI/res/values/config.xml
+++ b/packages/CarSystemUI/res/values/config.xml
@@ -123,7 +123,6 @@
<item>com.android.systemui.volume.VolumeUI</item>
<item>com.android.systemui.statusbar.phone.StatusBar</item>
<item>com.android.systemui.keyboard.KeyboardUI</item>
- <item>com.android.systemui.pip.PipUI</item>
<item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
<item>com.android.systemui.LatencyTester</item>
<item>com.android.systemui.globalactions.GlobalActionsComponent</item>
diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml
index 8359dac..f02a8e7 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 67fd5bb..fbdb516 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 e76373d..0db17ac 100644
--- a/packages/CarSystemUI/res/values/styles.xml
+++ b/packages/CarSystemUI/res/values/styles.xml
@@ -25,21 +25,29 @@
<item name="android:padding">22dp</item>
</style>
- <style name="TextAppearance.StatusBar.Clock"
- parent="@*android:style/TextAppearance.StatusBar.Icon">
- <item name="android:textSize">42sp</item>
- <item name="android:fontFamily">sans-serif-regular</item>
- <item name="android:textColor">@*android:color/car_grey_50</item>
+ <style name="TextAppearance.SystemBar.Clock"
+ parent="@*android:style/TextAppearance.StatusBar.Icon">
+ <item name="android:textSize">@dimen/car_body1_size</item>
+ <item name="android:textColor">@*android:color/car_headline3</item>
+ </style>
+
+ <style name="TextAppearance.SystemBar.Username"
+ parent="@android:style/TextAppearance.DeviceDefault">
+ <item name="android:textSize">@dimen/car_body3_size</item>
+ <item name="android:textColor">@color/system_bar_text_color</item>
</style>
<style name="TextAppearance.CarStatus" parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:textSize">@*android:dimen/car_body2_size</item>
- <item name="android:textColor">@*android:color/car_grey_50</item>
+ <item name="android:textColor">@color/system_bar_text_color</item>
</style>
<style name="NavigationBarButton">
- <item name="android:layout_height">96dp</item>
- <item name="android:layout_width">96dp</item>
+ <item name="android:layout_height">76dp</item>
+ <item name="android:layout_width">76dp</item>
+ <item name="android:layout_marginEnd">32dp</item>
+ <item name="android:padding">16dp</item>
+ <item name="android:gravity">center</item>
<item name="android:background">?android:attr/selectableItemBackground</item>
</style>
</resources>
\ No newline at end of file
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
index 1a6fdfa..51855dc 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java
@@ -20,7 +20,6 @@
import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.SystemUIModule;
-import com.android.systemui.pip.phone.dagger.PipModule;
import dagger.Subcomponent;
@@ -31,7 +30,6 @@
@Subcomponent(modules = {
CarComponentBinder.class,
DependencyProvider.class,
- PipModule.class,
SystemUIModule.class,
CarSystemUIModule.class,
CarSystemUIBinder.class})
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
index 3971e18..616e562 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java
@@ -29,7 +29,6 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.dagger.KeyguardModule;
import com.android.systemui.onehanded.OneHandedUI;
-import com.android.systemui.pip.PipUI;
import com.android.systemui.power.PowerUI;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsModule;
@@ -101,12 +100,6 @@
@ClassKey(OneHandedUI.class)
public abstract SystemUI bindOneHandedUI(OneHandedUI sysui);
- /** Inject into PipUI. */
- @Binds
- @IntoMap
- @ClassKey(PipUI.class)
- public abstract SystemUI bindPipUI(PipUI sysui);
-
/** Inject into PowerUI. */
@Binds
@IntoMap
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java
new file mode 100644
index 0000000..4cac445
--- /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 a729431..567baa9 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 @@
* 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 @@
}
private final int mAreaId;
- private final int mPropertyId;
private final int mPivotOffset;
private final int mGravity;
private final int mTextAppearanceRes;
@@ -100,12 +99,13 @@
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 @@
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 @@
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 @@
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 @@
}
/**
- * @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 @@
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 a4b6bfc..f7451dc 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 @@
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 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 @@
private final CarServiceProvider mCarServiceProvider;
private final Set<TemperatureView> mRegisteredViews = new HashSet<>();
- private CarHvacManager mHvacManager;
- private HashMap<HvacKey, List<TemperatureView>> mTempComponents = new HashMap<>();
+ private CarPropertyManager mCarPropertyManager;
+ private HashMap<Integer, 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 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);
- }
- } // 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 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));
+ }
+ }
+ }
+
+ @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 @@
}
/**
- * 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 @@
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 @@
}
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 @@
}
/**
- * 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 521a665..252f783 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 @@
* 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 @@
* @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 @@
}
/**
- * @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 6b903fa..3c0e0ac 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 @@
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 9584850..bf8cda3 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 @@
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 @@
}
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 51a8838..529083f4b 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 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 @@
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 @@
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 @@
mHvacControllerLazy.get().removeAllComponents();
mButtonSelectionStateController.removeAll();
mButtonRoleHolderController.removeAll();
+ mUserNameViewControllerLazy.get().removeAll();
}
/** Gets the top window if configured to do so. */
@@ -218,6 +223,7 @@
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 b8bf825..1418ace 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.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 @@
populateMaps();
readConfigs();
checkEnabledBarsHaveUniqueBarTypes();
+ checkAllOverlappingBarsHaveDifferentZOrders();
checkSystemBarEnabledForNotificationPanel();
setInsetPaddingsForOverlappingCorners();
sortSystemBarSidesByZOrder();
@@ -123,16 +125,60 @@
}
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 @@
}
}
- 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,43 +305,12 @@
}
private void setInsetPaddingsForOverlappingCorners() {
- setInsetPaddingForOverlappingCorner(TOP, LEFT);
- setInsetPaddingForOverlappingCorner(TOP, RIGHT);
- setInsetPaddingForOverlappingCorner(BOTTOM, LEFT);
- setInsetPaddingForOverlappingCorner(BOTTOM, RIGHT);
- }
-
- private void setInsetPaddingForOverlappingCorner(@SystemBarSide int horizontalSide,
- @SystemBarSide int verticalSide) {
-
- if (isVerticalBar(horizontalSide) || isHorizontalBar(verticalSide)) {
- Log.w(TAG, "configureBarPaddings: Returning immediately since the horizontal and "
- + "vertical sides were not provided correctly.");
- return;
- }
-
- SystemBarConfig horizontalBarConfig = mSystemBarConfigMap.get(horizontalSide);
- SystemBarConfig verticalBarConfig = mSystemBarConfigMap.get(verticalSide);
-
- 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 {
- 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 "
- + "determined. Determine which bar should be placed on top of the "
- + "other bar and change the Z-order in config.xml accordingly."
- );
- }
- }
+ Map<@SystemBarSide Integer, Boolean> systemBarVisibilityOnInit =
+ getSystemBarsVisibilityOnInit();
+ updateInsetPaddings(TOP, systemBarVisibilityOnInit);
+ updateInsetPaddings(BOTTOM, systemBarVisibilityOnInit);
+ updateInsetPaddings(LEFT, systemBarVisibilityOnInit);
+ updateInsetPaddings(RIGHT, systemBarVisibilityOnInit);
}
private void sortSystemBarSidesByZOrder() {
@@ -307,6 +328,75 @@
});
}
+ @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)) {
+ Log.w(TAG, "configureBarPaddings: Returning immediately since the horizontal and "
+ + "vertical sides were not provided correctly.");
+ return;
+ }
+
+ SystemBarConfig horizontalBarConfig = mSystemBarConfigMap.get(horizontalSide);
+ SystemBarConfig verticalBarConfig = mSystemBarConfigMap.get(verticalSide);
+
+ if (verticalBarConfig != null && horizontalBarConfig != null) {
+ int horizontalBarZOrder = horizontalBarConfig.getZOrder();
+ int verticalBarZOrder = verticalBarConfig.getZOrder();
+
+ 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 "
+ + "determined. Determine which bar should be placed on top of the "
+ + "other bar and change the Z-order in config.xml accordingly."
+ );
+ }
+ }
+ }
+
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 0000000..5ef8aa1
--- /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 0000000..e8850de
--- /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 e179ef1..9912657 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.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 @@
@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 0000000..e97d9d9
--- /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 0b164a2..0b3ac2a 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.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 @@
@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 @@
private ButtonRoleHolderController mButtonRoleHolderController;
@Mock
private HvacController mHvacController;
+ @Mock
+ private UserNameViewController mUserNameViewController;
@Before
public void setUp() throws Exception {
@@ -73,7 +80,7 @@
private CarNavigationBarController createNavigationBarController() {
return new CarNavigationBarController(mContext, mNavigationBarViewFactory,
mButtonSelectionStateController, () -> mHvacController,
- mButtonRoleHolderController,
+ () -> mUserNameViewController, mButtonRoleHolderController,
new SystemBarConfigs(mTestableResources.getResources()));
}
@@ -117,6 +124,11 @@
@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 @@
@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 8b15899..072358b 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 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 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 @@
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 @@
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 0000000..8f9e56e
--- /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 2821af9..0d54d7e 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 @@
"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/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 7f4f580..6db3d0b 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -516,7 +516,7 @@
android:excludeFromRecents="true"
android:visibleToInstantApps="true"/>
- <!-- started from PipUI -->
+ <!-- started from PipController -->
<activity
android:name=".pip.tv.PipMenuActivity"
android:permission="com.android.systemui.permission.SELF"
diff --git a/packages/SystemUI/README.md b/packages/SystemUI/README.md
index 148fabb..bd93c39 100644
--- a/packages/SystemUI/README.md
+++ b/packages/SystemUI/README.md
@@ -115,10 +115,6 @@
Shows the overlay controls when One handed is triggered.
-### [com.android.systemui.pip.PipUI](/packages/SystemUI/src/com/android/systemui/pip/PipUI.java)
-
-Shows the overlay controls when Pip is showing.
-
### [com.android.systemui.shortcut.ShortcutKeyDispatcher](/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java)
Dispatches shortcut to System UI components.
diff --git a/packages/SystemUI/res/layout-land-television/volume_dialog.xml b/packages/SystemUI/res/layout-land-television/volume_dialog.xml
index 56d847c..8179bf4 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 c0f0aa8..708dfd0 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 ae7f44d..b9e711e 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 4850e75..0ddd0e38 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 f048d62..412ed56 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-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 4aa4bda..40df8cd 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -403,7 +403,7 @@
<item quantity="one">%d cihaz</item>
</plurals>
<string name="quick_settings_notifications_label" msgid="3379631363952582758">"Bildirişlər"</string>
- <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"İşartı"</string>
+ <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Fənər"</string>
<string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Kamera istifadə olunur"</string>
<string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Mobil data"</string>
<string name="quick_settings_cellular_detail_data_usage" msgid="6105969068871138427">"Data istifadəsi"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 121a81d..acb6637 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -95,7 +95,7 @@
<string name="screenrecord_description" msgid="1123231719680353736">"Při nahrávání může systém Android zaznamenávat citlivé údaje, které jsou viditelné na obrazovce nebo které jsou přehrávány na zařízení. Týká se to hesel, údajů o platbě, fotek, zpráv a zvuků."</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Nahrát zvuk"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Zvuk zařízení"</string>
- <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Zvuk ze zařízení, například hudba, hovory a vyzváněcí tóny"</string>
+ <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Zvuk ze zařízení, například hudba, hovory a vyzvánění"</string>
<string name="screenrecord_mic_label" msgid="2111264835791332350">"Mikrofon"</string>
<string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"Zvuk a mikrofon zařízení"</string>
<string name="screenrecord_start" msgid="330991441575775004">"Spustit"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 4384749..5ca236b 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -691,7 +691,7 @@
<string name="notification_channel_minimized" msgid="6892672757877552959">"Αυτές οι ειδοποιήσεις θα ελαχιστοποιηθούν"</string>
<string name="notification_channel_silenced" msgid="1995937493874511359">"Αυτές οι ειδοποιήσεις θα εμφανίζονται σιωπηλά"</string>
<string name="notification_channel_unsilenced" msgid="94878840742161152">"Αυτές οι ειδοποιήσεις θα σας ενημερώνουν"</string>
- <string name="inline_blocking_helper" msgid="2891486013649543452">"Συνήθως απορρίπτετε αυτές τις ειδοποιήσεις. \nΝα εξακολουθήσουν να εμφανίζονται;"</string>
+ <string name="inline_blocking_helper" msgid="2891486013649543452">"Συνήθως παραβλέπετε αυτές τις ειδοποιήσεις. \nΝα εξακολουθήσουν να εμφανίζονται;"</string>
<string name="inline_done_button" msgid="6043094985588909584">"Τέλος"</string>
<string name="inline_ok_button" msgid="603075490581280343">"Εφαρμογή"</string>
<string name="inline_keep_showing" msgid="8736001253507073497">"Να συνεχίσουν να εμφανίζονται αυτές οι ειδοποιήσεις;"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 1d5ac1a..23bcd2c 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -552,7 +552,7 @@
<string name="monitoring_description_named_vpn" msgid="5749932930634037027">"<xliff:g id="VPN_APP">%1$s</xliff:g> aplikaziora konektatuta zaude eta hark sareko jarduerak gainbegira ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
<string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"<xliff:g id="VPN_APP_0">%1$s</xliff:g> eta <xliff:g id="VPN_APP_1">%2$s</xliff:g> aplikazioetara konektatuta zaude, eta haiek sareko jarduerak gainbegira ditzakete, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
<string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"<xliff:g id="VPN_APP">%1$s</xliff:g> aplikaziora dago konektatuta laneko profila, eta aplikazio horrek sareko jarduerak gainbegira ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
- <string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"<xliff:g id="VPN_APP">%1$s</xliff:g> aplikaziora konektatuta duzu profil pertsonala, eta aplikazio horrek sareko jarduerak gainbegira ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
+ <string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"<xliff:g id="VPN_APP">%1$s</xliff:g> aplikaziora konektatuta daukazu profil pertsonala, eta aplikazio horrek sareko jarduerak gainbegira ditzake, mezu elektronikoak, aplikazioak eta webguneak barne."</string>
<string name="monitoring_description_do_header_generic" msgid="6130190408164834986">"<xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> aplikazioak kudeatzen du gailu hau."</string>
<string name="monitoring_description_do_header_with_name" msgid="2696255132542779511">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> erakundeak <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> erabiltzen du gailua kudeatzeko."</string>
<string name="monitoring_description_do_body" msgid="7700878065625769970">"Gailuko ezarpenak, enpresa-sarbidea, aplikazioak eta datuak gainbegira eta kudea ditzake administratzaileak, baita gailuaren kokapen-informazioa ere."</string>
diff --git a/packages/SystemUI/res/values-land-television/dimens.xml b/packages/SystemUI/res/values-land-television/dimens.xml
index 90fc652..8237919 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 9e1b66f..b584dfe 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-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index d01ab8c..0331d26 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -403,7 +403,7 @@
<item quantity="one">%d peranti</item>
</plurals>
<string name="quick_settings_notifications_label" msgid="3379631363952582758">"Pemberitahuan"</string>
- <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Lampu suluh"</string>
+ <string name="quick_settings_flashlight_label" msgid="4904634272006284185">"Lampu Suluh"</string>
<string name="quick_settings_flashlight_camera_in_use" msgid="4820591564526512571">"Kamera sedang digunakan"</string>
<string name="quick_settings_cellular_detail_title" msgid="792977203299358893">"Data mudah alih"</string>
<string name="quick_settings_cellular_detail_data_usage" msgid="6105969068871138427">"Penggunaan data"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index e548a96..196b4ad 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -500,8 +500,8 @@
<string name="battery_saver_notification_title" msgid="8419266546034372562">"ब्याट्री सेभर अन छ"</string>
<string name="battery_saver_notification_text" msgid="2617841636449016951">"प्रदर्शन र पृष्ठभूमि डेटा घटाउँनुहोस्"</string>
<string name="battery_saver_notification_action_text" msgid="6022091913807026887">"ब्याट्री सेभर अफ गर्नुहोस्"</string>
- <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ले तपाईंको स्क्रिनमा देख्न सकिने सबै जानकारी अथवा रेकर्ड वा cast गर्दा तपाईंको यन्त्रबाट प्ले गरिएका कुरामाथि पहुँच राख्न सक्ने छ। यसअन्तर्गत पासवर्ड, भुक्तानीका विवरण, तस्बिर, सन्देश र तपाईंले प्ले गर्ने अडियो जस्ता जानकारी समावेश हुन्छन्।"</string>
- <string name="media_projection_dialog_service_text" msgid="958000992162214611">"यो कार्य प्रदान गर्ने सेवाले तपाईंको स्क्रिनमा देख्न सकिने सबै जानकारी अथवा रेकर्ड वा cast गर्दा तपाईंको यन्त्रबाट प्ले गरिएका कुरामाथि पहुँच राख्न सक्ने छ। यसअन्तर्गत पासवर्ड, भुक्तानीका विवरण, तस्बिर, सन्देश र तपाईंले प्ले गर्ने अडियो जस्ता जानकारी समावेश हुन्छन्।"</string>
+ <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ले तपाईंको स्क्रिनमा देख्न सकिने सबै जानकारी अथवा रेकर्ड वा cast गर्दा तपाईंको यन्त्रबाट प्ले गरिएका कुरामाथि पहुँच राख्न सक्ने छ। यसअन्तर्गत पासवर्ड, भुक्तानीका विवरण, फोटो, सन्देश र तपाईंले प्ले गर्ने अडियो जस्ता जानकारी समावेश हुन्छन्।"</string>
+ <string name="media_projection_dialog_service_text" msgid="958000992162214611">"यो कार्य प्रदान गर्ने सेवाले तपाईंको स्क्रिनमा देख्न सकिने सबै जानकारी अथवा रेकर्ड वा cast गर्दा तपाईंको यन्त्रबाट प्ले गरिएका कुरामाथि पहुँच राख्न सक्ने छ। यसअन्तर्गत पासवर्ड, भुक्तानीका विवरण, फोटो, सन्देश र तपाईंले प्ले गर्ने अडियो जस्ता जानकारी समावेश हुन्छन्।"</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"रेकर्ड गर्न वा cast गर्न थाल्ने हो?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> मार्फत रेकर्ड गर्न वा cast गर्न थाल्ने हो?"</string>
<string name="media_projection_remember_text" msgid="6896767327140422951">"फेरि नदेखाउनुहोस्"</string>
@@ -716,7 +716,7 @@
<string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"फोनको सेटिङका आधारमा घन्टी बज्न वा कम्पन हुन सक्छ। <xliff:g id="APP_NAME">%1$s</xliff:g> का वार्तालापहरू पूर्वनिर्धारित रूपमा बबलमा देखाइन्छन्।"</string>
<string name="notification_channel_summary_bubble" msgid="7235935211580860537">"फ्लोटिङ सर्टकटमार्फत यो सामग्रीतर्फ तपाईंको ध्यान आकर्षित गर्दछ।"</string>
<string name="notification_channel_summary_automatic" msgid="5813109268050235275">"सिस्टमलाई यो सूचना आउँदा ध्वनि बज्नु पर्छ वा कम्पन हुनु पर्छ भन्ने कुराको निधो गर्न दिनुहोस्"</string>
- <string name="notification_channel_summary_priority" msgid="7952654515769021553">"वार्तालाप खण्डको सिरानमा देखा पर्छ, तैरने बबलका रूपमा देखा पर्छ, लक स्क्रिनमा प्रोफाइल तस्बिर देखाइन्छ"</string>
+ <string name="notification_channel_summary_priority" msgid="7952654515769021553">"वार्तालाप खण्डको सिरानमा देखा पर्छ, तैरने बबलका रूपमा देखा पर्छ, लक स्क्रिनमा प्रोफाइल फोटो देखाइन्छ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"सेटिङ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string>
<string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा वार्तालापसम्बन्धी सुविधा प्रयोग गर्न मिल्दैन"</string>
@@ -1019,7 +1019,7 @@
<string name="priority_onboarding_title" msgid="2893070698479227616">"वार्तालापको प्राथमिकता निर्धारण गरी \"महत्त्वपूर्ण\" बनाइयो"</string>
<string name="priority_onboarding_behavior" msgid="5342816047020432929">"महत्वपूर्ण वार्तालापहरू:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"वार्तालाप खण्डको सिरानमा देखिने छन्"</string>
- <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"लक स्क्रिनमा प्रोफाइल तस्बिर देखाउने छन्"</string>
+ <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"लक स्क्रिनमा प्रोफाइल फोटो देखाउने छन्"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"एपहरूमाथि तैरिने बबलका रूपमा देखाइयोस्"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"बाधा नपुऱ्याउनुहोस् मोडलाई बेवास्ता गरियोस्"</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"बुझेँ"</string>
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
index b2d057b..4a94038 100644
--- a/packages/SystemUI/res/values-television/config.xml
+++ b/packages/SystemUI/res/values-television/config.xml
@@ -33,7 +33,6 @@
<item>com.android.systemui.power.PowerUI</item>
<item>com.android.systemui.media.RingtonePlayer</item>
<item>com.android.systemui.keyboard.KeyboardUI</item>
- <item>com.android.systemui.pip.PipUI</item>
<item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
<item>@string/config_systemUIVendorServiceComponent</item>
<item>com.android.systemui.SliceBroadcastRelayHandler</item>
diff --git a/packages/SystemUI/res/values-television/integers.xml b/packages/SystemUI/res/values-television/integers.xml
index 91e83cc..587497e 100644
--- a/packages/SystemUI/res/values-television/integers.xml
+++ b/packages/SystemUI/res/values-television/integers.xml
@@ -17,6 +17,7 @@
<resources>
<!-- The position of the volume dialog on the screen.
See com.android.systemui.volume.VolumeDialogImpl.
- Value 81 corresponds to BOTTOM|CENTER_HORIZONTAL. -->
- <integer name="volume_dialog_gravity">81</integer>
-</resources>
\ No newline at end of file
+ Value 81 corresponds to BOTTOM|CENTER_HORIZONTAL.
+ Value 21 corresponds to RIGHT|CENTER_VERTICAL. -->
+ <integer name="volume_dialog_gravity">21</integer>
+</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 130bb4f..7faa2a4 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -306,7 +306,6 @@
<item>com.android.systemui.power.PowerUI</item>
<item>com.android.systemui.media.RingtonePlayer</item>
<item>com.android.systemui.keyboard.KeyboardUI</item>
- <item>com.android.systemui.pip.PipUI</item>
<item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item>
<item>@string/config_systemUIVendorServiceComponent</item>
<item>com.android.systemui.util.leak.GarbageMonitor$Service</item>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index d12f010..7b80f00 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/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index c354241..1027329 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -2519,13 +2519,11 @@
if (isUserUnlocked(getCurrentUser())) {
return false;
}
- Intent homeIntent = new Intent(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_HOME);
- ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(homeIntent,
- 0 /* flags */);
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME);
+ ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivityAsUser(homeIntent,
+ 0 /* flags */, getCurrentUser());
- // TODO(b/160971249): Replace in the future by resolving activity as user.
- if (resolveInfo == null && mIsAutomotive) {
+ if (resolveInfo == null) {
Log.w(TAG, "resolveNeedsSlowUnlockTransition: returning false since activity "
+ "could not be resolved.");
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
index 34f721c..128af37 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.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 @@
/**
* 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 @@
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 @@
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 @@
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 @@
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/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 2622593..4bea067 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -22,7 +22,6 @@
import com.android.systemui.SystemUIAppComponentFactory;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardSliceProvider;
-import com.android.systemui.pip.phone.dagger.PipModule;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.InjectionInflationController;
@@ -36,7 +35,6 @@
@Subcomponent(modules = {
DefaultComponentBinder.class,
DependencyProvider.class,
- PipModule.class,
SystemUIBinder.class,
SystemUIModule.class,
SystemUIDefaultModule.class})
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 9dfd9f8..c331bd3 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -29,7 +29,6 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.dagger.KeyguardModule;
import com.android.systemui.onehanded.OneHandedUI;
-import com.android.systemui.pip.PipUI;
import com.android.systemui.power.PowerUI;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsModule;
@@ -97,12 +96,6 @@
@ClassKey(OneHandedUI.class)
public abstract SystemUI bindOneHandedUI(OneHandedUI sysui);
- /** Inject into PipUI. */
- @Binds
- @IntoMap
- @ClassKey(PipUI.class)
- public abstract SystemUI bindPipUI(PipUI sysui);
-
/** Inject into PowerUI. */
@Binds
@IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 686531a..b2ad19b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -562,7 +562,10 @@
decoder, info, source -> decoder.isMutableRequired = true
}
} catch (e: IOException) {
- e.printStackTrace()
+ Log.e(TAG, "Unable to load bitmap", e)
+ null
+ } catch (e: RuntimeException) {
+ Log.e(TAG, "Unable to load bitmap", e)
null
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java b/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
deleted file mode 100644
index 38744fe..0000000
--- a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.pip;
-
-import android.content.res.Configuration;
-
-import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
-
-import java.io.PrintWriter;
-
-
-public interface BasePipManager {
- void showPictureInPictureMenu();
- default void expandPip() {}
- default void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {}
- void onConfigurationChanged(Configuration newConfig);
- default void setShelfHeight(boolean visible, int height) {}
- default void setPinnedStackAnimationType(int animationType) {}
- default void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) {}
- default void dump(PrintWriter pw) {}
-}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/Pip.java b/packages/SystemUI/src/com/android/systemui/pip/Pip.java
new file mode 100644
index 0000000..b068370
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/Pip.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.pip;
+
+import android.content.res.Configuration;
+import android.media.session.MediaController;
+
+import com.android.systemui.pip.tv.PipController;
+import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
+
+import java.io.PrintWriter;
+
+/**
+ * Interface to engage picture in picture feature.
+ */
+public interface Pip {
+ /**
+ * Called when showing Pip menu.
+ */
+ void showPictureInPictureMenu();
+
+ /**
+ * Registers {@link com.android.systemui.pip.tv.PipController.Listener} that gets called.
+ * whenever receiving notification on changes in PIP.
+ */
+ default void addListener(PipController.Listener listener) {
+ }
+
+ /**
+ * Registers a {@link com.android.systemui.pip.tv.PipController.MediaListener} to PipController.
+ */
+ default void addMediaListener(PipController.MediaListener listener) {
+ }
+
+ /**
+ * Closes PIP (PIPed activity and PIP system UI).
+ */
+ default void closePip() {
+ }
+
+ /**
+ * Expand PIP, it's possible that specific request to activate the window via Alt-tab.
+ */
+ default void expandPip() {
+ }
+
+ /**
+ * Get current play back state. (e.g: Used in TV)
+ *
+ * @return The state of defined in PipController.
+ */
+ default int getPlaybackState() {
+ return 0;
+ }
+
+ /**
+ * Get MediaController.
+ *
+ * @return The MediaController instance.
+ */
+ default MediaController getMediaController() {
+ return null;
+ }
+
+ /**
+ * Hides the PIP menu.
+ */
+ void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback);
+
+ /**
+ * Returns {@code true} if PIP is shown.
+ */
+ default boolean isPipShown() {
+ return false;
+ }
+
+ /**
+ * Moves the PIPed activity to the fullscreen and closes PIP system UI.
+ */
+ default void movePipToFullscreen() {
+ }
+
+ /**
+ * Called when configuration change invoked.
+ */
+ void onConfigurationChanged(Configuration newConfig);
+
+ /**
+ * Removes a {@link PipController.Listener} from PipController.
+ */
+ default void removeListener(PipController.Listener listener) {
+ }
+
+ /**
+ * Removes a {@link com.android.systemui.pip.tv.PipController.MediaListener} from PipController.
+ */
+ default void removeMediaListener(PipController.MediaListener listener) {
+ }
+
+ /**
+ * Resize the Pip to the appropriate size for the input state.
+ *
+ * @param state In Pip state also used to determine the new size for the Pip.
+ */
+ default void resizePinnedStack(int state) {
+ }
+
+ /**
+ * Resumes resizing operation on the Pip that was previously suspended.
+ *
+ * @param reason The reason resizing operations on the Pip was suspended.
+ */
+ default void resumePipResizing(int reason) {
+ }
+
+ /**
+ * Sets both shelf visibility and its height.
+ *
+ * @param visible visibility of shelf.
+ * @param height to specify the height for shelf.
+ */
+ default void setShelfHeight(boolean visible, int height) {
+ }
+
+ /**
+ * Set the pinned stack with {@link PipAnimationController.AnimationType}
+ *
+ * @param animationType The pre-defined {@link PipAnimationController.AnimationType}
+ */
+ default void setPinnedStackAnimationType(int animationType) {
+ }
+
+ /**
+ * Registers the pinned stack animation listener.
+ *
+ * @param listener The listener of pinned stack animation.
+ */
+ default void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) {
+ }
+
+ /**
+ * Suspends resizing operation on the Pip until {@link #resumePipResizing} is called.
+ *
+ * @param reason The reason for suspending resizing operations on the Pip.
+ */
+ default void suspendPipResizing(int reason) {
+ }
+
+ /**
+ * Dump the current state and information if need.
+ *
+ * @param pw The stream to dump information to.
+ */
+ default void dump(PrintWriter pw) {
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index c956702..6f44090 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -47,6 +47,7 @@
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
+import android.util.Rational;
import android.util.Size;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
@@ -684,13 +685,16 @@
* {@link PictureInPictureParams} would affect the bounds.
*/
private boolean applyPictureInPictureParams(@NonNull PictureInPictureParams params) {
- final boolean changed = (mPictureInPictureParams == null) || !Objects.equals(
- mPictureInPictureParams.getAspectRatioRational(), params.getAspectRatioRational());
- if (changed) {
- mPictureInPictureParams = params;
+ final Rational currentAspectRatio =
+ mPictureInPictureParams != null ? mPictureInPictureParams.getAspectRatioRational()
+ : null;
+ final boolean aspectRatioChanged = !Objects.equals(currentAspectRatio,
+ params.getAspectRatioRational());
+ mPictureInPictureParams = params;
+ if (aspectRatioChanged) {
mPipBoundsHandler.onAspectRatioChanged(params.getAspectRatio());
}
- return changed;
+ return aspectRatioChanged;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
deleted file mode 100644
index 2cd1e20..0000000
--- a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.pip;
-
-import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.os.UserHandle;
-import android.os.UserManager;
-
-import com.android.systemui.SystemUI;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
-import com.android.systemui.statusbar.CommandQueue;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-import javax.inject.Inject;
-
-/**
- * Controls the picture-in-picture window.
- */
-@SysUISingleton
-public class PipUI extends SystemUI implements CommandQueue.Callbacks {
-
- private final CommandQueue mCommandQueue;
- private BasePipManager mPipManager;
-
- @Inject
- public PipUI(Context context, CommandQueue commandQueue,
- BasePipManager pipManager) {
- super(context);
- mCommandQueue = commandQueue;
- mPipManager = pipManager;
- }
-
- @Override
- public void start() {
- PackageManager pm = mContext.getPackageManager();
- boolean supportsPip = pm.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
- if (!supportsPip) {
- return;
- }
-
- // Ensure that we are the primary user's SystemUI.
- final int processUser = UserManager.get(mContext).getUserHandle();
- if (processUser != UserHandle.USER_SYSTEM) {
- throw new IllegalStateException("Non-primary Pip component not currently supported.");
- }
-
- mCommandQueue.addCallback(this);
- }
-
- @Override
- public void showPictureInPictureMenu() {
- mPipManager.showPictureInPictureMenu();
- }
-
- public void expandPip() {
- mPipManager.expandPip();
- }
-
- public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {
- mPipManager.hidePipMenu(onStartCallback, onEndCallback);
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- if (mPipManager == null) {
- return;
- }
-
- mPipManager.onConfigurationChanged(newConfig);
- }
-
- public void setShelfHeight(boolean visible, int height) {
- if (mPipManager == null) {
- return;
- }
-
- mPipManager.setShelfHeight(visible, height);
- }
-
- public void setPinnedStackAnimationType(int animationType) {
- if (mPipManager != null) {
- mPipManager.setPinnedStackAnimationType(animationType);
- }
- }
-
- public void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) {
- if (mPipManager != null) {
- mPipManager.setPinnedStackAnimationListener(listener);
- }
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mPipManager == null) {
- return;
- }
-
- mPipManager.dump(pw);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java
similarity index 89%
rename from packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
rename to packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java
index 5ef5b90..1a805da 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipController.java
@@ -18,6 +18,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static com.android.systemui.pip.PipAnimationController.isOutPipDirection;
@@ -28,11 +29,14 @@
import android.app.RemoteAction;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.util.Log;
import android.util.Pair;
import android.view.DisplayInfo;
@@ -44,7 +48,7 @@
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.model.SysUiState;
-import com.android.systemui.pip.BasePipManager;
+import com.android.systemui.pip.Pip;
import com.android.systemui.pip.PipBoundsHandler;
import com.android.systemui.pip.PipSurfaceTransactionHelper;
import com.android.systemui.pip.PipTaskOrganizer;
@@ -55,25 +59,20 @@
import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.WindowManagerWrapper;
-import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.FloatingContentCoordinator;
-import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
import java.io.PrintWriter;
-import java.util.Optional;
-
-import javax.inject.Inject;
/**
* Manages the picture-in-picture (PIP) UI and states for Phones.
*/
@SysUISingleton
-public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitionCallback {
- private static final String TAG = "PipManager";
+public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallback {
+ private static final String TAG = "PipController";
private Context mContext;
private IActivityManager mActivityManager;
@@ -87,15 +86,15 @@
private DisplayController mDisplayController;
private InputConsumerController mInputConsumerController;
private PipAppOpsListener mAppOpsListener;
+ private PipBoundsHandler mPipBoundsHandler;
private PipMediaController mMediaController;
private PipTouchHandler mTouchHandler;
- private PipTaskOrganizer mPipTaskOrganizer;
private PipSurfaceTransactionHelper mPipSurfaceTransactionHelper;
private IPinnedStackAnimationListener mPinnedStackAnimationRecentsListener;
private boolean mIsInFixedRotation;
- protected PipBoundsHandler mPipBoundsHandler;
protected PipMenuActivityController mMenuController;
+ protected PipTaskOrganizer mPipTaskOrganizer;
/**
* Handler for display rotation changes.
@@ -127,7 +126,7 @@
// not during the fixed rotation. In fixed rotation case, app is about to enter PiP
// and we need the offsets preserved to calculate the destination bounds.
if (!mIsInFixedRotation) {
- mPipBoundsHandler.setShelfHeight(false , 0);
+ mPipBoundsHandler.setShelfHeight(false, 0);
mPipBoundsHandler.onImeVisibilityChanged(false, 0);
mTouchHandler.onShelfVisibilityChanged(false, 0);
mTouchHandler.onImeVisibilityChanged(false, 0);
@@ -201,7 +200,7 @@
/**
* Handler for messages from the PIP controller.
*/
- private class PipManagerPinnedStackListener extends PinnedStackListener {
+ private class PipControllerPinnedStackListener extends PinnedStackListener {
@Override
public void onListenerRegistered(IPinnedStackController controller) {
mHandler.post(() -> mTouchHandler.setPinnedStackController(controller));
@@ -253,44 +252,55 @@
public ConfigurationController.ConfigurationListener mOverlayChangedListener =
new ConfigurationController.ConfigurationListener() {
- @Override
- public void onOverlayChanged() {
- mHandler.post(() -> {
- mPipBoundsHandler.onOverlayChanged(mContext, mContext.getDisplay());
- updateMovementBounds(null /* toBounds */,
- false /* fromRotation */, false /* fromImeAdjustment */,
- false /* fromShelfAdjustment */, null /* windowContainerTransaction */);
- });
- }
- };
+ @Override
+ public void onOverlayChanged() {
+ mHandler.post(() -> {
+ mPipBoundsHandler.onOverlayChanged(mContext, mContext.getDisplay());
+ updateMovementBounds(null /* toBounds */,
+ false /* fromRotation */, false /* fromImeAdjustment */,
+ false /* fromShelfAdjustment */,
+ null /* windowContainerTransaction */);
+ });
+ }
+ };
- @Inject
- public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
+ public PipController(Context context, BroadcastDispatcher broadcastDispatcher,
ConfigurationController configController,
DeviceConfigProxy deviceConfig,
DisplayController displayController,
- Optional<SplitScreen> splitScreenOptional,
FloatingContentCoordinator floatingContentCoordinator,
SysUiState sysUiState,
- PipUiEventLogger pipUiEventLogger,
- ShellTaskOrganizer shellTaskOrganizer) {
+ PipBoundsHandler pipBoundsHandler,
+ PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ PipTaskOrganizer pipTaskOrganizer,
+ PipUiEventLogger pipUiEventLogger) {
mContext = context;
mActivityManager = ActivityManager.getService();
+ PackageManager pm = context.getPackageManager();
+ boolean supportsPip = pm.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
+ if (!supportsPip) {
+ return;
+ }
+
+ // Ensure that we are the primary user's SystemUI.
+ final int processUser = UserManager.get(context).getUserHandle();
+ if (processUser != UserHandle.USER_SYSTEM) {
+ throw new IllegalStateException("Non-primary Pip component not currently supported.");
+ }
+
try {
WindowManagerWrapper.getInstance().addPinnedStackListener(
- new PipManagerPinnedStackListener());
+ new PipControllerPinnedStackListener());
} catch (RemoteException e) {
Log.e(TAG, "Failed to register pinned stack listener", e);
}
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
mDisplayController = displayController;
- mPipBoundsHandler = new PipBoundsHandler(mContext);
- mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(context, configController);
- mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler,
- mPipSurfaceTransactionHelper, splitScreenOptional, mDisplayController,
- pipUiEventLogger, shellTaskOrganizer);
+ mPipBoundsHandler = pipBoundsHandler;
+ mPipSurfaceTransactionHelper = pipSurfaceTransactionHelper;
+ mPipTaskOrganizer = pipTaskOrganizer;
mPipTaskOrganizer.registerPipTransitionCallback(this);
mInputConsumerController = InputConsumerController.getPipInputConsumer();
mMediaController = new PipMediaController(context, mActivityManager, broadcastDispatcher);
@@ -450,6 +460,7 @@
mTmpDisplayInfo.rotation);
}
+ @Override
public void dump(PrintWriter pw) {
final String innerPrefix = " ";
pw.println(TAG);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
index f6853ec..50d20d3 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
@@ -329,6 +329,10 @@
mInputMonitor.pilferPointers();
}
if (mThresholdCrossed) {
+ if (mPipMenuActivityController.isMenuVisible()) {
+ mPipMenuActivityController.hideMenuWithoutResize();
+ mPipMenuActivityController.hideMenu();
+ }
final Rect currentPipBounds = mMotionHelper.getBounds();
mLastResizeBounds.set(TaskResizingAlgorithm.resizeDrag(x, y,
mDownPoint.x, mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x,
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipModule.java b/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipModule.java
deleted file mode 100644
index c8b6982..0000000
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipModule.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.pip.phone.dagger;
-
-import com.android.systemui.pip.BasePipManager;
-import com.android.systemui.pip.phone.PipManager;
-
-import dagger.Binds;
-import dagger.Module;
-
-/**
- * Dagger Module for Phone PIP.
- */
-@Module
-public abstract class PipModule {
-
- /** Binds PipManager as the default BasePipManager. */
- @Binds
- public abstract BasePipManager providePipManager(PipManager pipManager);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java
similarity index 91%
rename from packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
rename to packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java
index a388fa3..3b3235f 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipController.java
@@ -20,7 +20,6 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import android.annotation.NonNull;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityTaskManager;
@@ -51,35 +50,32 @@
import com.android.systemui.UiOffloadThread;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.pip.BasePipManager;
+import com.android.systemui.pip.Pip;
import com.android.systemui.pip.PipBoundsHandler;
import com.android.systemui.pip.PipSurfaceTransactionHelper;
import com.android.systemui.pip.PipTaskOrganizer;
-import com.android.systemui.pip.PipUiEventLogger;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.WindowManagerWrapper;
-import com.android.systemui.stackdivider.SplitScreen;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.DisplayController;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
-import javax.inject.Inject;
-
/**
* Manages the picture-in-picture (PIP) UI and states.
*/
@SysUISingleton
-public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitionCallback {
- private static final String TAG = "PipManager";
+public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallback {
+ private static final String TAG = "PipController";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
/**
+ * Unknown or invalid state
+ */
+ public static final int STATE_UNKNOWN = -1;
+ /**
* State when there's no PIP.
*/
public static final int STATE_NO_PIP = 0;
@@ -147,7 +143,7 @@
private boolean mImeVisible;
private int mImeHeightAdjustment;
- private final PinnedStackListener mPinnedStackListener = new PipManagerPinnedStackListener();
+ private final PinnedStackListener mPinnedStackListener = new PipControllerPinnedStackListener();
private final Runnable mResizePinnedStackRunnable = new Runnable() {
@Override
@@ -189,7 +185,7 @@
/**
* Handler for messages from the PIP controller.
*/
- private class PipManagerPinnedStackListener extends PinnedStackListener {
+ private class PipControllerPinnedStackListener extends PinnedStackListener {
@Override
public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
mHandler.post(() -> {
@@ -231,20 +227,19 @@
}
}
- @Inject
- public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
- ConfigurationController configController,
- DisplayController displayController,
- Optional<SplitScreen> splitScreenOptional,
- @NonNull PipUiEventLogger pipUiEventLogger,
- ShellTaskOrganizer shellTaskOrganizer) {
+ public PipController(Context context, BroadcastDispatcher broadcastDispatcher,
+ PipBoundsHandler pipBoundsHandler,
+ PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ PipTaskOrganizer pipTaskOrganizer) {
if (mInitialized) {
return;
}
mInitialized = true;
mContext = context;
- mPipBoundsHandler = new PipBoundsHandler(mContext);
+ mPipNotification = new PipNotification(context, broadcastDispatcher,
+ Optional.of(this).get());
+ mPipBoundsHandler = pipBoundsHandler;
// Ensure that we have the display info in case we get calls to update the bounds before the
// listener calls back
final DisplayInfo displayInfo = new DisplayInfo();
@@ -253,10 +248,8 @@
mResizeAnimationDuration = context.getResources()
.getInteger(R.integer.config_pipResizeAnimationDuration);
- mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(context, configController);
- mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler,
- mPipSurfaceTransactionHelper, splitScreenOptional, displayController,
- pipUiEventLogger, shellTaskOrganizer);
+ mPipSurfaceTransactionHelper = pipSurfaceTransactionHelper;
+ mPipTaskOrganizer = pipTaskOrganizer;
mPipTaskOrganizer.registerPipTransitionCallback(this);
mActivityTaskManager = ActivityTaskManager.getService();
ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
@@ -278,8 +271,6 @@
} catch (RemoteException | UnsupportedOperationException e) {
Log.e(TAG, "Failed to register pinned stack listener", e);
}
-
- mPipNotification = new PipNotification(context, broadcastDispatcher, this);
}
private void loadConfigurationsAndApply(Configuration newConfig) {
@@ -359,7 +350,7 @@
/**
* Moves the PIPed activity to the fullscreen and closes PIP system UI.
*/
- void movePipToFullscreen() {
+ public void movePipToFullscreen() {
if (DEBUG) Log.d(TAG, "movePipToFullscreen(), current state=" + getStateDescription());
mPipTaskId = TASK_ID_NO_PIP;
@@ -372,34 +363,41 @@
/**
* Suspends resizing operation on the Pip until {@link #resumePipResizing} is called
+ *
* @param reason The reason for suspending resizing operations on the Pip.
*/
public void suspendPipResizing(int reason) {
- if (DEBUG) Log.d(TAG,
- "suspendPipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
+ if (DEBUG) {
+ Log.d(TAG,
+ "suspendPipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
+ }
mSuspendPipResizingReason |= reason;
}
/**
* Resumes resizing operation on the Pip that was previously suspended.
+ *
* @param reason The reason resizing operations on the Pip was suspended.
*/
public void resumePipResizing(int reason) {
if ((mSuspendPipResizingReason & reason) == 0) {
return;
}
- if (DEBUG) Log.d(TAG,
- "resumePipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
+ if (DEBUG) {
+ Log.d(TAG,
+ "resumePipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
+ }
mSuspendPipResizingReason &= ~reason;
mHandler.post(mResizePinnedStackRunnable);
}
/**
* Resize the Pip to the appropriate size for the input state.
+ *
* @param state In Pip state also used to determine the new size for the Pip.
*/
- void resizePinnedStack(int state) {
+ public void resizePinnedStack(int state) {
if (DEBUG) {
Log.d(TAG, "resizePinnedStack() state=" + stateToName(state) + ", current state="
+ getStateDescription(), new Exception());
@@ -411,10 +409,12 @@
}
if (mSuspendPipResizingReason != 0) {
mResumeResizePinnedStackRunnableState = state;
- if (DEBUG) Log.d(TAG, "resizePinnedStack() deferring"
- + " mSuspendPipResizingReason=" + mSuspendPipResizingReason
- + " mResumeResizePinnedStackRunnableState="
- + stateToName(mResumeResizePinnedStackRunnableState));
+ if (DEBUG) {
+ Log.d(TAG, "resizePinnedStack() deferring"
+ + " mSuspendPipResizingReason=" + mSuspendPipResizingReason
+ + " mResumeResizePinnedStackRunnableState="
+ + stateToName(mResumeResizePinnedStackRunnableState));
+ }
return;
}
mState = state;
@@ -471,28 +471,28 @@
}
/**
- * Adds a {@link Listener} to PipManager.
+ * Adds a {@link Listener} to PipController.
*/
public void addListener(Listener listener) {
mListeners.add(listener);
}
/**
- * Removes a {@link Listener} from PipManager.
+ * Removes a {@link Listener} from PipController.
*/
public void removeListener(Listener listener) {
mListeners.remove(listener);
}
/**
- * Adds a {@link MediaListener} to PipManager.
+ * Adds a {@link MediaListener} to PipController.
*/
public void addMediaListener(MediaListener listener) {
mMediaListeners.add(listener);
}
/**
- * Removes a {@link MediaListener} from PipManager.
+ * Removes a {@link MediaListener} from PipController.
*/
public void removeMediaListener(MediaListener listener) {
mMediaListeners.remove(listener);
@@ -568,16 +568,21 @@
/**
* Gets the {@link android.media.session.MediaController} for the PIPed activity.
*/
- MediaController getMediaController() {
+ public MediaController getMediaController() {
return mPipMediaController;
}
+ @Override
+ public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {
+
+ }
+
/**
* Returns the PIPed activity's playback state.
* This returns one of {@link #PLAYBACK_STATE_PLAYING}, {@link #PLAYBACK_STATE_PAUSED},
* or {@link #PLAYBACK_STATE_UNAVAILABLE}.
*/
- int getPlaybackState() {
+ public int getPlaybackState() {
if (mPipMediaController == null || mPipMediaController.getPlaybackState() == null) {
return PLAYBACK_STATE_UNAVAILABLE;
}
@@ -673,7 +678,8 @@
};
@Override
- public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) { }
+ public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) {
+ }
@Override
public void onPipTransitionFinished(ComponentName activity, int direction) {
@@ -701,7 +707,7 @@
* Invoked when an activity is pinned and PIP manager is set corresponding information.
* Classes must use this instead of {@link android.app.ITaskStackListener.onActivityPinned}
* because there's no guarantee for the PIP manager be return relavent information
- * correctly. (e.g. {@link isPipShown}).
+ * correctly. (e.g. {@link Pip.isPipShown}).
*/
void onPipEntered(String packageName);
/** Invoked when a PIPed activity is closed. */
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java
index 05bb882..4ecd52f 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java
@@ -27,12 +27,14 @@
import android.view.View;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.pip.Pip;
import com.android.wm.shell.R;
import java.util.ArrayList;
import java.util.List;
-
-import javax.inject.Inject;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
/**
* Controller for {@link PipControlsView}.
@@ -43,9 +45,9 @@
private static final float DISABLED_ACTION_ALPHA = 0.54f;
private final PipControlsView mView;
- private final PipManager mPipManager;
private final LayoutInflater mLayoutInflater;
private final Handler mHandler;
+ private final Optional<Pip> mPipOptional;
private final PipControlButtonView mPlayPauseButtonView;
private MediaController mMediaController;
private PipControlButtonView mFocusedChild;
@@ -73,12 +75,14 @@
@Override
public void onViewAttachedToWindow(View v) {
updateMediaController();
- mPipManager.addMediaListener(mPipMediaListener);
+ mPipOptional.ifPresent(
+ pip -> pip.addMediaListener(mPipMediaListener));
}
@Override
public void onViewDetachedFromWindow(View v) {
- mPipManager.removeMediaListener(mPipMediaListener);
+ mPipOptional.ifPresent(
+ pip -> pip.removeMediaListener(mPipMediaListener));
}
};
@@ -89,7 +93,7 @@
}
};
- private final PipManager.MediaListener mPipMediaListener = this::updateMediaController;
+ private final PipController.MediaListener mPipMediaListener = this::updateMediaController;
private final View.OnFocusChangeListener
mFocusChangeListener =
@@ -105,12 +109,11 @@
};
- @Inject
- public PipControlsViewController(PipControlsView view, PipManager pipManager,
+ public PipControlsViewController(PipControlsView view, Optional<Pip> pipOptional,
LayoutInflater layoutInflater, @Main Handler handler) {
super();
mView = view;
- mPipManager = pipManager;
+ mPipOptional = pipOptional;
mLayoutInflater = layoutInflater;
mHandler = handler;
@@ -121,12 +124,14 @@
View fullButtonView = mView.getFullButtonView();
fullButtonView.setOnFocusChangeListener(mFocusChangeListener);
- fullButtonView.setOnClickListener(v -> mPipManager.movePipToFullscreen());
+ fullButtonView.setOnClickListener(
+ v -> mPipOptional.ifPresent(pip -> pip.movePipToFullscreen())
+ );
View closeButtonView = mView.getCloseButtonView();
closeButtonView.setOnFocusChangeListener(mFocusChangeListener);
closeButtonView.setOnClickListener(v -> {
- mPipManager.closePip();
+ mPipOptional.ifPresent(pip -> pip.closePip());
if (mListener != null) {
mListener.onClosed();
}
@@ -139,24 +144,29 @@
if (mMediaController == null || mMediaController.getPlaybackState() == null) {
return;
}
- if (mPipManager.getPlaybackState() == PipManager.PLAYBACK_STATE_PAUSED) {
- mMediaController.getTransportControls().play();
- } else if (mPipManager.getPlaybackState() == PipManager.PLAYBACK_STATE_PLAYING) {
- mMediaController.getTransportControls().pause();
- }
+ mPipOptional.ifPresent(pip -> {
+ if (pip.getPlaybackState() == PipController.PLAYBACK_STATE_PAUSED) {
+ mMediaController.getTransportControls().play();
+ } else if (pip.getPlaybackState() == PipController.PLAYBACK_STATE_PLAYING) {
+ mMediaController.getTransportControls().pause();
+ }
+ });
+
// View will be updated later in {@link mMediaControllerCallback}
});
}
private void updateMediaController() {
- MediaController newController = mPipManager.getMediaController();
- if (mMediaController == newController) {
+ AtomicReference<MediaController> newController = new AtomicReference<>();
+ mPipOptional.ifPresent(pip -> newController.set(pip.getMediaController()));
+
+ if (newController.get() == null || mMediaController == newController.get()) {
return;
}
if (mMediaController != null) {
mMediaController.unregisterCallback(mMediaControllerCallback);
}
- mMediaController = newController;
+ mMediaController = newController.get();
if (mMediaController != null) {
mMediaController.registerCallback(mMediaControllerCallback);
}
@@ -210,12 +220,14 @@
// Hide the media session buttons
mPlayPauseButtonView.setVisibility(View.GONE);
} else {
- int state = mPipManager.getPlaybackState();
- if (state == PipManager.PLAYBACK_STATE_UNAVAILABLE) {
+ AtomicInteger state = new AtomicInteger(PipController.STATE_UNKNOWN);
+ mPipOptional.ifPresent(pip -> state.set(pip.getPlaybackState()));
+ if (state.get() == PipController.STATE_UNKNOWN
+ || state.get() == PipController.PLAYBACK_STATE_UNAVAILABLE) {
mPlayPauseButtonView.setVisibility(View.GONE);
} else {
mPlayPauseButtonView.setVisibility(View.VISIBLE);
- if (state == PipManager.PLAYBACK_STATE_PLAYING) {
+ if (state.get() == PipController.PLAYBACK_STATE_PLAYING) {
mPlayPauseButtonView.setImageResource(R.drawable.pip_ic_pause_white);
mPlayPauseButtonView.setText(R.string.pip_pause);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
index 7037403..7e812d9 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
@@ -25,17 +25,20 @@
import android.os.Bundle;
import android.util.Log;
+import com.android.systemui.pip.Pip;
import com.android.systemui.pip.tv.dagger.TvPipComponent;
import com.android.wm.shell.R;
import java.util.Collections;
+import java.util.Optional;
import javax.inject.Inject;
/**
* Activity to show the PIP menu to control PIP.
*/
-public class PipMenuActivity extends Activity implements PipManager.Listener {
+
+public class PipMenuActivity extends Activity implements PipController.Listener {
private static final String TAG = "PipMenuActivity";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -43,7 +46,7 @@
private final TvPipComponent.Builder mPipComponentBuilder;
private TvPipComponent mTvPipComponent;
- private final PipManager mPipManager;
+ private final Optional<Pip> mPipOptional;
private Animator mFadeInAnimation;
private Animator mFadeOutAnimation;
@@ -51,10 +54,11 @@
private PipControlsViewController mPipControlsViewController;
@Inject
- public PipMenuActivity(TvPipComponent.Builder pipComponentBuilder, PipManager pipManager) {
+ public PipMenuActivity(TvPipComponent.Builder pipComponentBuilder,
+ Optional<Pip> pipOptional) {
super();
mPipComponentBuilder = pipComponentBuilder;
- mPipManager = pipManager;
+ mPipOptional = pipOptional;
}
@Override
@@ -62,15 +66,17 @@
if (DEBUG) Log.d(TAG, "onCreate()");
super.onCreate(bundle);
- if (!mPipManager.isPipShown()) {
- finish();
- }
+ mPipOptional.ifPresent(pip -> {
+ if (!pip.isPipShown()) {
+ finish();
+ }
+ });
setContentView(R.layout.tv_pip_menu);
mTvPipComponent = mPipComponentBuilder.pipControlsView(
findViewById(R.id.pip_controls)).build();
mPipControlsViewController = mTvPipComponent.getPipControlsViewController();
- mPipManager.addListener(this);
+ mPipOptional.ifPresent(pip -> pip.addListener(this));
mRestorePipSizeWhenClose = true;
mFadeInAnimation = AnimatorInflater.loadAnimator(
@@ -98,7 +104,7 @@
if (DEBUG) Log.d(TAG, " > restoring to the default position");
// When PIP menu activity is closed, restore to the default position.
- mPipManager.resizePinnedStack(PipManager.STATE_PIP);
+ mPipOptional.ifPresent(pip -> pip.resizePinnedStack(PipController.STATE_PIP));
}
finish();
}
@@ -125,9 +131,9 @@
if (DEBUG) Log.d(TAG, "onDestroy()");
super.onDestroy();
- mPipManager.removeListener(this);
- mPipManager.resumePipResizing(
- PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
+ mPipOptional.ifPresent(pip -> pip.removeListener(this));
+ mPipOptional.ifPresent(pip -> pip.resumePipResizing(
+ PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH));
}
@Override
@@ -178,8 +184,8 @@
if (DEBUG) Log.d(TAG, "onPipResizeAboutToStart()");
finish();
- mPipManager.suspendPipResizing(
- PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
+ mPipOptional.ifPresent(pip -> pip.suspendPipResizing(
+ PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
index 5e5de58..78569ed 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
@@ -48,14 +48,14 @@
public class PipNotification {
private static final String TAG = "PipNotification";
private static final String NOTIFICATION_TAG = PipNotification.class.getSimpleName();
- private static final boolean DEBUG = PipManager.DEBUG;
+ private static final boolean DEBUG = PipController.DEBUG;
private static final String ACTION_MENU = "PipNotification.menu";
private static final String ACTION_CLOSE = "PipNotification.close";
private final PackageManager mPackageManager;
- private final PipManager mPipManager;
+ private final PipController mPipController;
private final NotificationManager mNotificationManager;
private final Notification.Builder mNotificationBuilder;
@@ -70,7 +70,7 @@
private String mMediaTitle;
private Bitmap mArt;
- private PipManager.Listener mPipListener = new PipManager.Listener() {
+ private PipController.Listener mPipListener = new PipController.Listener() {
@Override
public void onPipEntered(String packageName) {
mPackageName = packageName;
@@ -124,26 +124,27 @@
}
};
- private final PipManager.MediaListener mPipMediaListener = new PipManager.MediaListener() {
- @Override
- public void onMediaControllerChanged() {
- MediaController newController = mPipManager.getMediaController();
- if (mMediaController == newController) {
- return;
- }
- if (mMediaController != null) {
- mMediaController.unregisterCallback(mMediaControllerCallback);
- }
- mMediaController = newController;
- if (mMediaController != null) {
- mMediaController.registerCallback(mMediaControllerCallback);
- }
- if (updateMediaControllerMetadata() && mNotified) {
- // update notification
- notifyPipNotification();
- }
- }
- };
+ private final PipController.MediaListener mPipMediaListener =
+ new PipController.MediaListener() {
+ @Override
+ public void onMediaControllerChanged() {
+ MediaController newController = mPipController.getMediaController();
+ if (newController == null || mMediaController == newController) {
+ return;
+ }
+ if (mMediaController != null) {
+ mMediaController.unregisterCallback(mMediaControllerCallback);
+ }
+ mMediaController = newController;
+ if (mMediaController != null) {
+ mMediaController.registerCallback(mMediaControllerCallback);
+ }
+ if (updateMediaControllerMetadata() && mNotified) {
+ // update notification
+ notifyPipNotification();
+ }
+ }
+ };
private final BroadcastReceiver mEventReceiver = new BroadcastReceiver() {
@Override
@@ -153,17 +154,17 @@
}
switch (intent.getAction()) {
case ACTION_MENU:
- mPipManager.showPictureInPictureMenu();
+ mPipController.showPictureInPictureMenu();
break;
case ACTION_CLOSE:
- mPipManager.closePip();
+ mPipController.closePip();
break;
}
}
};
public PipNotification(Context context, BroadcastDispatcher broadcastDispatcher,
- PipManager pipManager) {
+ PipController pipController) {
mPackageManager = context.getPackageManager();
mNotificationManager = (NotificationManager) context.getSystemService(
@@ -177,9 +178,9 @@
.setContentIntent(createPendingIntent(context, ACTION_MENU))
.setDeleteIntent(createPendingIntent(context, ACTION_CLOSE)));
- mPipManager = pipManager;
- mPipManager.addListener(mPipListener);
- mPipManager.addMediaListener(mPipMediaListener);
+ mPipController = pipController;
+ pipController.addListener(mPipListener);
+ pipController.addMediaListener(mPipMediaListener);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_MENU);
@@ -190,7 +191,7 @@
}
/**
- * Called by {@link PipManager} when the configuration is changed.
+ * Called by {@link PipController} when the configuration is changed.
*/
void onConfigurationChanged(Context context) {
Resources res = context.getResources();
@@ -227,8 +228,8 @@
private boolean updateMediaControllerMetadata() {
String title = null;
Bitmap art = null;
- if (mPipManager.getMediaController() != null) {
- MediaMetadata metadata = mPipManager.getMediaController().getMetadata();
+ if (mPipController.getMediaController() != null) {
+ MediaMetadata metadata = mPipController.getMediaController().getMetadata();
if (metadata != null) {
title = metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE);
if (TextUtils.isEmpty(title)) {
@@ -248,6 +249,7 @@
return false;
}
+
private String getNotificationTitle() {
if (!TextUtils.isEmpty(mMediaTitle)) {
return mMediaTitle;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/PipModule.java b/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/PipModule.java
deleted file mode 100644
index 52b38a9..0000000
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/PipModule.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.pip.tv.dagger;
-
-import android.app.Activity;
-
-import com.android.systemui.pip.BasePipManager;
-import com.android.systemui.pip.tv.PipManager;
-import com.android.systemui.pip.tv.PipMenuActivity;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.multibindings.ClassKey;
-import dagger.multibindings.IntoMap;
-
-/**
- * Dagger module for TV Pip.
- */
-@Module(subcomponents = {TvPipComponent.class})
-public abstract class PipModule {
-
- /** Binds PipManager as the default BasePipManager. */
- @Binds
- public abstract BasePipManager providePipManager(PipManager pipManager);
-
-
- /** Inject into PipMenuActivity. */
- @Binds
- @IntoMap
- @ClassKey(PipMenuActivity.class)
- public abstract Activity providePipMenuActivity(PipMenuActivity activity);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 263bbdb..62b35f9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -75,8 +75,8 @@
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.onehanded.OneHandedUI;
+import com.android.systemui.pip.Pip;
import com.android.systemui.pip.PipAnimationController;
-import com.android.systemui.pip.PipUI;
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.shared.recents.IOverviewProxy;
@@ -122,7 +122,7 @@
private static final long MAX_BACKOFF_MILLIS = 10 * 60 * 1000;
private final Context mContext;
- private final PipUI mPipUI;
+ private final Optional<Pip> mPipOptional;
private final Optional<Lazy<StatusBar>> mStatusBarOptionalLazy;
private final Optional<SplitScreen> mSplitScreenOptional;
private SysUiState mSysUiState;
@@ -388,7 +388,8 @@
}
long token = Binder.clearCallingIdentity();
try {
- mPipUI.setShelfHeight(visible, shelfHeight);
+ mPipOptional.ifPresent(
+ pip -> pip.setShelfHeight(visible, shelfHeight));
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -413,7 +414,9 @@
}
long token = Binder.clearCallingIdentity();
try {
- mPipUI.setPinnedStackAnimationType(PipAnimationController.ANIM_TYPE_ALPHA);
+ mPipOptional.ifPresent(
+ pip -> pip.setPinnedStackAnimationType(
+ PipAnimationController.ANIM_TYPE_ALPHA));
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -426,7 +429,8 @@
}
long token = Binder.clearCallingIdentity();
try {
- mPipUI.setPinnedStackAnimationListener(listener);
+ mPipOptional.ifPresent(
+ pip -> pip.setPinnedStackAnimationListener(listener));
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -603,14 +607,16 @@
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Inject
public OverviewProxyService(Context context, CommandQueue commandQueue,
- Lazy<NavigationBarController> navBarControllerLazy, NavigationModeController navModeController,
+ Lazy<NavigationBarController> navBarControllerLazy,
+ NavigationModeController navModeController,
NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
- PipUI pipUI, Optional<SplitScreen> splitScreenOptional,
+ Optional<Pip> pipOptional,
+ Optional<SplitScreen> splitScreenOptional,
Optional<Lazy<StatusBar>> statusBarOptionalLazy, OneHandedUI oneHandedUI,
BroadcastDispatcher broadcastDispatcher) {
super(broadcastDispatcher);
mContext = context;
- mPipUI = pipUI;
+ mPipOptional = pipOptional;
mStatusBarOptionalLazy = statusBarOptionalLazy;
mHandler = new Handler();
mNavBarControllerLazy = navBarControllerLazy;
@@ -916,6 +922,7 @@
/**
* Notifies the Launcher of split screen size changes
+ *
* @param secondaryWindowBounds Bounds of the secondary window including the insets
* @param secondaryWindowInsets stable insets received by the secondary window
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
index c023400..24e912e 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 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 05f5ea8..f8fe067 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 @@
*/
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 60883f0..c24d3fc 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 @@
* 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 @@
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 @@
}
@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 @@
mController.updateShowEmptyShadeView();
updateFooter();
}
+
+ updateSpeedBumpIndex();
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -5002,6 +5008,8 @@
mController.updateShowEmptyShadeView();
updateFooter();
}
+
+ updateSpeedBumpIndex();
}
public void addContainerViewAt(View v, int index) {
@@ -5011,6 +5019,8 @@
mController.updateShowEmptyShadeView();
updateFooter();
}
+
+ updateSpeedBumpIndex();
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -5237,6 +5247,7 @@
protected void setStatusBarState(int statusBarState) {
mStatusBarState = statusBarState;
mAmbientState.setStatusBarState(statusBarState);
+ updateSpeedBumpIndex();
}
void onStatePostChange(boolean fromShadeLocked) {
@@ -5777,7 +5788,7 @@
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void updateSpeedBumpIndex() {
+ private void updateSpeedBumpIndex() {
int speedBumpIndex = 0;
int currentIndex = 0;
final int N = getChildCount();
@@ -5799,7 +5810,7 @@
}
}
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 a0b49ac..8d792ab 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 @@
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 169058a..f627835 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 void updateNotificationViews(String reason) {
mNotificationStackScrollLayoutController.updateSectionBoundaries(reason);
- mNotificationStackScrollLayoutController.updateSpeedBumpIndex();
mNotificationStackScrollLayoutController.updateFooter();
mNotificationIconAreaController.updateNotificationIcons(createVisibleEntriesList());
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
index 9a44bf1..22fa010 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
@@ -17,12 +17,11 @@
package com.android.systemui.tv;
import com.android.systemui.dagger.GlobalRootComponent;
-import com.android.systemui.pip.tv.dagger.PipModule;
import dagger.Binds;
import dagger.Module;
-@Module(includes = {PipModule.class})
+@Module()
interface TvSystemUIBinder {
@Binds
GlobalRootComponent bindGlobalRootComponent(TvGlobalRootComponent globalRootComponent);
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index d727bfb..c5bb9c1 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -62,7 +62,7 @@
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.wmshell.WMShellModule;
+import com.android.systemui.wmshell.TvWMShellModule;
import javax.inject.Named;
@@ -76,7 +76,7 @@
*/
@Module(includes = {
QSModule.class,
- WMShellModule.class
+ TvWMShellModule.class,
},
subcomponents = {
})
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
new file mode 100644
index 0000000..d8cb280
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wmshell;
+
+import android.content.Context;
+import android.os.Handler;
+import android.view.IWindowManager;
+
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.pip.Pip;
+import com.android.systemui.pip.PipBoundsHandler;
+import com.android.systemui.pip.PipSurfaceTransactionHelper;
+import com.android.systemui.pip.PipTaskOrganizer;
+import com.android.systemui.pip.PipUiEventLogger;
+import com.android.systemui.pip.tv.PipController;
+import com.android.systemui.pip.tv.PipNotification;
+import com.android.systemui.pip.tv.dagger.TvPipComponent;
+import com.android.systemui.stackdivider.SplitScreen;
+import com.android.systemui.stackdivider.SplitScreenController;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TransactionPool;
+
+import java.util.Optional;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Provides dependencies from {@link com.android.wm.shell} which could be customized among different
+ * branches of SystemUI.
+ */
+// TODO(b/162923491): Move most of these dependencies into WMSingleton scope.
+@Module(includes = WMShellBaseModule.class, subcomponents = {TvPipComponent.class})
+public class TvWMShellModule {
+ @SysUISingleton
+ @Provides
+ static DisplayImeController provideDisplayImeController(IWindowManager wmService,
+ DisplayController displayController, @Main Handler mainHandler,
+ TransactionPool transactionPool) {
+ return new DisplayImeController(wmService, displayController, mainHandler, transactionPool);
+ }
+
+ @SysUISingleton
+ @Provides
+ static Pip providePipController(Context context,
+ BroadcastDispatcher broadcastDispatcher,
+ PipBoundsHandler pipBoundsHandler,
+ PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ PipTaskOrganizer pipTaskOrganizer) {
+ return new PipController(context, broadcastDispatcher, pipBoundsHandler,
+ pipSurfaceTransactionHelper, pipTaskOrganizer);
+ }
+
+ @SysUISingleton
+ @Provides
+ static SplitScreen provideSplitScreen(Context context,
+ DisplayController displayController, SystemWindows systemWindows,
+ DisplayImeController displayImeController, @Main Handler handler,
+ TransactionPool transactionPool, ShellTaskOrganizer shellTaskOrganizer) {
+ return new SplitScreenController(context, displayController, systemWindows,
+ displayImeController, handler, transactionPool, shellTaskOrganizer);
+ }
+
+ @SysUISingleton
+ @Provides
+ static PipNotification providePipNotification(Context context,
+ BroadcastDispatcher broadcastDispatcher,
+ PipController pipController) {
+ return new PipNotification(context, broadcastDispatcher, pipController);
+ }
+
+ @SysUISingleton
+ @Provides
+ static PipBoundsHandler providesPipBoundsHandler(Context context) {
+ return new PipBoundsHandler(context);
+ }
+
+ @SysUISingleton
+ @Provides
+ static PipTaskOrganizer providesPipTaskOrganizer(Context context,
+ PipBoundsHandler pipBoundsHandler,
+ PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ Optional<SplitScreen> splitScreenOptional, DisplayController displayController,
+ PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) {
+ return new PipTaskOrganizer(context, pipBoundsHandler,
+ pipSurfaceTransactionHelper, splitScreenOptional, displayController,
+ pipUiEventLogger, shellTaskOrganizer);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index ee404ca..e1e18a2 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -25,10 +25,12 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.pip.Pip;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.tracing.ProtoTraceable;
import com.android.systemui.stackdivider.SplitScreen;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.tracing.nano.SystemUiTraceProto;
import com.android.wm.shell.common.DisplayImeController;
@@ -46,20 +48,27 @@
* Proxy in SysUiScope to delegate events to controllers in WM Shell library.
*/
@SysUISingleton
-public final class WMShell extends SystemUI implements ProtoTraceable<SystemUiTraceProto> {
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+public final class WMShell extends SystemUI implements ProtoTraceable<SystemUiTraceProto>,
+ CommandQueue.Callbacks {
+ private final CommandQueue mCommandQueue;
private final DisplayImeController mDisplayImeController;
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final Optional<Pip> mPipOptional;
private final Optional<SplitScreen> mSplitScreenOptional;
private final ProtoTracer mProtoTracer;
@Inject
- WMShell(Context context, KeyguardUpdateMonitor keyguardUpdateMonitor,
+ public WMShell(Context context, CommandQueue commandQueue,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
DisplayImeController displayImeController,
+ Optional<Pip> pipOptional,
Optional<SplitScreen> splitScreenOptional,
ProtoTracer protoTracer) {
super(context);
+ mCommandQueue = commandQueue;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mDisplayImeController = displayImeController;
+ mPipOptional = pipOptional;
mSplitScreenOptional = splitScreenOptional;
mProtoTracer = protoTracer;
mProtoTracer.add(this);
@@ -70,11 +79,22 @@
// This is to prevent circular init problem by separating registration step out of its
// constructor. And make sure the initialization of DisplayImeController won't depend on
// specific feature anymore.
+ mCommandQueue.addCallback(this);
mDisplayImeController.startMonitorDisplays();
+ mPipOptional.ifPresent(this::initPip);
mSplitScreenOptional.ifPresent(this::initSplitScreen);
}
+ private void initPip(Pip pip) {
+ mCommandQueue.addCallback(new CommandQueue.Callbacks() {
+ @Override
+ public void showPictureInPictureMenu() {
+ pip.showPictureInPictureMenu();
+ }
+ });
+ }
+
private void initSplitScreen(SplitScreen splitScreen) {
mKeyguardUpdateMonitor.registerCallback(new KeyguardUpdateMonitorCallback() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 0a3172ce..cdf85fb 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -23,8 +23,11 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.pip.Pip;
+import com.android.systemui.pip.PipSurfaceTransactionHelper;
import com.android.systemui.pip.PipUiEventLogger;
import com.android.systemui.stackdivider.SplitScreen;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.FloatingContentCoordinator;
import com.android.wm.shell.ShellTaskOrganizer;
@@ -76,6 +79,13 @@
@SysUISingleton
@Provides
+ static PipSurfaceTransactionHelper providesPipSurfaceTransactionHelper(Context context,
+ ConfigurationController configController) {
+ return new PipSurfaceTransactionHelper(context, configController);
+ }
+
+ @SysUISingleton
+ @Provides
static SystemWindows provideSystemWindows(DisplayController displayController,
IWindowManager wmService) {
return new SystemWindows(displayController, wmService);
@@ -90,5 +100,8 @@
}
@BindsOptionalOf
+ abstract Pip optionalPip();
+
+ @BindsOptionalOf
abstract SplitScreen optionalSplitScreen();
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 6a2ca44..1870b76 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -20,16 +20,29 @@
import android.os.Handler;
import android.view.IWindowManager;
+import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.pip.Pip;
+import com.android.systemui.pip.PipBoundsHandler;
+import com.android.systemui.pip.PipSurfaceTransactionHelper;
+import com.android.systemui.pip.PipTaskOrganizer;
+import com.android.systemui.pip.PipUiEventLogger;
+import com.android.systemui.pip.phone.PipController;
import com.android.systemui.stackdivider.SplitScreen;
import com.android.systemui.stackdivider.SplitScreenController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.util.DeviceConfigProxy;
+import com.android.systemui.util.FloatingContentCoordinator;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TransactionPool;
+import java.util.Optional;
+
import dagger.Module;
import dagger.Provides;
@@ -50,6 +63,26 @@
@SysUISingleton
@Provides
+ static Pip providePipController(Context context,
+ BroadcastDispatcher broadcastDispatcher,
+ ConfigurationController configController,
+ DeviceConfigProxy deviceConfig,
+ DisplayController displayController,
+ FloatingContentCoordinator floatingContentCoordinator,
+ SysUiState sysUiState,
+ PipBoundsHandler pipBoundsHandler,
+ PipSurfaceTransactionHelper surfaceTransactionHelper,
+ PipTaskOrganizer pipTaskOrganizer,
+ PipUiEventLogger pipUiEventLogger) {
+ return new PipController(context, broadcastDispatcher, configController, deviceConfig,
+ displayController, floatingContentCoordinator, sysUiState, pipBoundsHandler,
+ surfaceTransactionHelper,
+ pipTaskOrganizer,
+ pipUiEventLogger);
+ }
+
+ @SysUISingleton
+ @Provides
static SplitScreen provideSplitScreen(Context context,
DisplayController displayController, SystemWindows systemWindows,
DisplayImeController displayImeController, @Main Handler handler,
@@ -57,4 +90,23 @@
return new SplitScreenController(context, displayController, systemWindows,
displayImeController, handler, transactionPool, shellTaskOrganizer);
}
+
+ @SysUISingleton
+ @Provides
+ static PipBoundsHandler providesPipBoundsHandler(Context context) {
+ return new PipBoundsHandler(context);
+ }
+
+ @SysUISingleton
+ @Provides
+ static PipTaskOrganizer providesPipTaskOrganizer(Context context,
+ PipBoundsHandler pipBoundsHandler,
+ PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
+ Optional<SplitScreen> splitScreenOptional, DisplayController displayController,
+ PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) {
+ return new PipTaskOrganizer(context, pipBoundsHandler,
+ pipSurfaceTransactionHelper, splitScreenOptional, displayController,
+ pipUiEventLogger, shellTaskOrganizer);
+ }
+
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
index ee151c4..cdbc647 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 @@
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.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.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.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 @@
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 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 @@
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 8089561..b0f2a89 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.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 @@
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 5264458..f48e6ea79 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 @@
.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 8cb5f3e..6976422 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 @@
}
@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 @@
@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 @@
@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/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
new file mode 100644
index 0000000..2f3c86d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wmshell;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.pip.Pip;
+import com.android.systemui.pip.tv.PipController;
+import com.android.systemui.stackdivider.SplitScreen;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.tracing.ProtoTracer;
+import com.android.wm.shell.common.DisplayImeController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Optional;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WMShellTest extends SysuiTestCase {
+
+ Instrumentation mInstrumentation;
+ WMShell mWMShell;
+ @Mock Context mContext;
+ @Mock CommandQueue mCommandQueue;
+ @Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock DisplayImeController mDisplayImeController;
+ @Mock Optional<Pip> mPipOptional;
+ @Mock Optional<SplitScreen> mSplitScreenOptional;
+ @Mock PipController mPipController;
+ @Mock ProtoTracer mProtoTracer;
+
+ @Before
+ public void setUp() throws Exception {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ MockitoAnnotations.initMocks(this);
+ mWMShell = new WMShell(mContext, mCommandQueue, mKeyguardUpdateMonitor,
+ mDisplayImeController, mPipOptional, mSplitScreenOptional, mProtoTracer);
+ mWMShell.start();
+ when(mPipOptional.get()).thenReturn(mPipController);
+ }
+
+ @Test
+ public void testWMShellRegisterCommandQueue() {
+ verify(mCommandQueue, times(1)).addCallback(mWMShell);
+ }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
index c70dfcc..df4a52e 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
@@ -287,7 +287,9 @@
/**
* Sends down events to the view hierarchy for all pointers which are not already being
- * delivered with original down location. i.e. pointers that are not yet injected.
+ * delivered with original down location. i.e. pointers that are not yet injected. The down time
+ * is also replaced by the original one.
+ *
*
* @param prototype The prototype from which to create the injected events.
* @param policyFlags The policy flags associated with the event.
@@ -296,7 +298,7 @@
// Inject the injected pointers.
int pointerIdBits = 0;
final int pointerCount = prototype.getPointerCount();
- final MotionEvent event = computeEventWithOriginalDown(prototype);
+ final MotionEvent event = computeInjectionDownEvent(prototype);
for (int i = 0; i < pointerCount; i++) {
final int pointerId = prototype.getPointerId(i);
// Do not send event for already delivered pointers.
@@ -313,7 +315,7 @@
}
}
- private MotionEvent computeEventWithOriginalDown(MotionEvent prototype) {
+ private MotionEvent computeInjectionDownEvent(MotionEvent prototype) {
final int pointerCount = prototype.getPointerCount();
if (pointerCount != mState.getReceivedPointerTracker().getReceivedPointerDownCount()) {
Slog.w(LOG_TAG, "The pointer count doesn't match the received count.");
@@ -336,7 +338,10 @@
MotionEvent event =
MotionEvent.obtain(
prototype.getDownTime(),
- prototype.getEventTime(),
+ // The event time is used for downTime while sending ACTION_DOWN. We adjust
+ // it to avoid the motion velocity is too fast in the beginning after
+ // Delegating.
+ prototype.getDownTime(),
prototype.getAction(),
pointerCount,
properties,
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index eb38f51..7b9728cb 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -393,12 +393,14 @@
.toString());
long identity = Binder.clearCallingIdentity();
try {
- return PendingIntent.getActivity(getContext(),
+ return PendingIntent.getActivityAsUser(getContext(),
0 /* request code */,
NotificationAccessConfirmationActivityContract.launcherIntent(
userId, component, packageTitle),
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT
- | PendingIntent.FLAG_CANCEL_CURRENT);
+ | PendingIntent.FLAG_CANCEL_CURRENT,
+ null /* options */,
+ new UserHandle(userId));
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -612,8 +614,8 @@
}
}
- 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 dbdcc87..bcb7bfa 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -489,7 +489,7 @@
* @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 @@
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 @@
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 @@
}
// 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 44258d1..a5d2011 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 @@
@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 @@
@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 @@
@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 @@
@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 @@
mActivityManagerService.dumpBinderCacheContents(fd, pw, args);
} finally {
- if (mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.useFreezer()) {
- Process.enableFreezer(true);
- }
+ mActivityManagerService.mOomAdjuster.mCachedAppOptimizer.enableFreezer(true);
}
}
}
@@ -5778,9 +5762,7 @@
}
private boolean isAppBad(final String processName, final int uid) {
- synchronized (this) {
- return mAppErrors.isBadProcessLocked(processName, uid);
- }
+ return mAppErrors.isBadProcess(processName, uid);
}
// NOTE: this is an internal method used by the OnShellCommand implementation only and should
@@ -16834,14 +16816,14 @@
}
}
- 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 +18753,16 @@
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/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 5268359..5d429d3 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -50,6 +50,7 @@
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.ProcessMap;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
@@ -96,7 +97,11 @@
* a minimum amount of time; they are removed from it when they are
* later restarted (hopefully due to some user action). The value is the
* time it was added to the list.
+ *
+ * Access is synchronized on the container object itself, and no other
+ * locks may be acquired while holding that one.
*/
+ @GuardedBy("mBadProcesses")
private final ProcessMap<BadProcessInfo> mBadProcesses = new ProcessMap<>();
@@ -114,76 +119,81 @@
mProcessCrashTimes.clear();
mProcessCrashTimesPersistent.clear();
mProcessCrashShowDialogTimes.clear();
- mBadProcesses.clear();
+ synchronized (mBadProcesses) {
+ mBadProcesses.clear();
+ }
}
void dumpDebug(ProtoOutputStream proto, long fieldId, String dumpPackage) {
- if (mProcessCrashTimes.getMap().isEmpty() && mBadProcesses.getMap().isEmpty()) {
- return;
- }
-
- final long token = proto.start(fieldId);
- final long now = SystemClock.uptimeMillis();
- proto.write(AppErrorsProto.NOW_UPTIME_MS, now);
-
- if (!mProcessCrashTimes.getMap().isEmpty()) {
- final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
- final int procCount = pmap.size();
- for (int ip = 0; ip < procCount; ip++) {
- final long ctoken = proto.start(AppErrorsProto.PROCESS_CRASH_TIMES);
- final String pname = pmap.keyAt(ip);
- final SparseArray<Long> uids = pmap.valueAt(ip);
- final int uidCount = uids.size();
-
- proto.write(AppErrorsProto.ProcessCrashTime.PROCESS_NAME, pname);
- for (int i = 0; i < uidCount; i++) {
- final int puid = uids.keyAt(i);
- final ProcessRecord r = mService.getProcessNames().get(pname, puid);
- if (dumpPackage != null && (r == null || !r.pkgList.containsKey(dumpPackage))) {
- continue;
- }
- final long etoken = proto.start(AppErrorsProto.ProcessCrashTime.ENTRIES);
- proto.write(AppErrorsProto.ProcessCrashTime.Entry.UID, puid);
- proto.write(AppErrorsProto.ProcessCrashTime.Entry.LAST_CRASHED_AT_MS,
- uids.valueAt(i));
- proto.end(etoken);
- }
- proto.end(ctoken);
+ synchronized (mBadProcesses) {
+ if (mProcessCrashTimes.getMap().isEmpty() && mBadProcesses.getMap().isEmpty()) {
+ return;
}
- }
+ final long token = proto.start(fieldId);
+ final long now = SystemClock.uptimeMillis();
+ proto.write(AppErrorsProto.NOW_UPTIME_MS, now);
- if (!mBadProcesses.getMap().isEmpty()) {
- final ArrayMap<String, SparseArray<BadProcessInfo>> pmap = mBadProcesses.getMap();
- final int processCount = pmap.size();
- for (int ip = 0; ip < processCount; ip++) {
- final long btoken = proto.start(AppErrorsProto.BAD_PROCESSES);
- final String pname = pmap.keyAt(ip);
- final SparseArray<BadProcessInfo> uids = pmap.valueAt(ip);
- final int uidCount = uids.size();
+ if (!mProcessCrashTimes.getMap().isEmpty()) {
+ final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap();
+ final int procCount = pmap.size();
+ for (int ip = 0; ip < procCount; ip++) {
+ final long ctoken = proto.start(AppErrorsProto.PROCESS_CRASH_TIMES);
+ final String pname = pmap.keyAt(ip);
+ final SparseArray<Long> uids = pmap.valueAt(ip);
+ final int uidCount = uids.size();
- proto.write(AppErrorsProto.BadProcess.PROCESS_NAME, pname);
- for (int i = 0; i < uidCount; i++) {
- final int puid = uids.keyAt(i);
- final ProcessRecord r = mService.getProcessNames().get(pname, puid);
- if (dumpPackage != null && (r == null
- || !r.pkgList.containsKey(dumpPackage))) {
- continue;
+ proto.write(AppErrorsProto.ProcessCrashTime.PROCESS_NAME, pname);
+ for (int i = 0; i < uidCount; i++) {
+ final int puid = uids.keyAt(i);
+ final ProcessRecord r = mService.getProcessNames().get(pname, puid);
+ if (dumpPackage != null
+ && (r == null || !r.pkgList.containsKey(dumpPackage))) {
+ continue;
+ }
+ final long etoken = proto.start(AppErrorsProto.ProcessCrashTime.ENTRIES);
+ proto.write(AppErrorsProto.ProcessCrashTime.Entry.UID, puid);
+ proto.write(AppErrorsProto.ProcessCrashTime.Entry.LAST_CRASHED_AT_MS,
+ uids.valueAt(i));
+ proto.end(etoken);
}
- final BadProcessInfo info = uids.valueAt(i);
- final long etoken = proto.start(AppErrorsProto.BadProcess.ENTRIES);
- proto.write(AppErrorsProto.BadProcess.Entry.UID, puid);
- proto.write(AppErrorsProto.BadProcess.Entry.CRASHED_AT_MS, info.time);
- proto.write(AppErrorsProto.BadProcess.Entry.SHORT_MSG, info.shortMsg);
- proto.write(AppErrorsProto.BadProcess.Entry.LONG_MSG, info.longMsg);
- proto.write(AppErrorsProto.BadProcess.Entry.STACK, info.stack);
- proto.end(etoken);
+ proto.end(ctoken);
}
- proto.end(btoken);
- }
- }
- proto.end(token);
+ }
+
+ if (!mBadProcesses.getMap().isEmpty()) {
+ final ArrayMap<String, SparseArray<BadProcessInfo>> pmap = mBadProcesses.getMap();
+ final int processCount = pmap.size();
+ for (int ip = 0; ip < processCount; ip++) {
+ final long btoken = proto.start(AppErrorsProto.BAD_PROCESSES);
+ final String pname = pmap.keyAt(ip);
+ final SparseArray<BadProcessInfo> uids = pmap.valueAt(ip);
+ final int uidCount = uids.size();
+
+ proto.write(AppErrorsProto.BadProcess.PROCESS_NAME, pname);
+ for (int i = 0; i < uidCount; i++) {
+ final int puid = uids.keyAt(i);
+ final ProcessRecord r = mService.getProcessNames().get(pname, puid);
+ if (dumpPackage != null && (r == null
+ || !r.pkgList.containsKey(dumpPackage))) {
+ continue;
+ }
+ final BadProcessInfo info = uids.valueAt(i);
+ final long etoken = proto.start(AppErrorsProto.BadProcess.ENTRIES);
+ proto.write(AppErrorsProto.BadProcess.Entry.UID, puid);
+ proto.write(AppErrorsProto.BadProcess.Entry.CRASHED_AT_MS, info.time);
+ proto.write(AppErrorsProto.BadProcess.Entry.SHORT_MSG, info.shortMsg);
+ proto.write(AppErrorsProto.BadProcess.Entry.LONG_MSG, info.longMsg);
+ proto.write(AppErrorsProto.BadProcess.Entry.STACK, info.stack);
+ proto.end(etoken);
+ }
+ proto.end(btoken);
+ }
+ }
+
+ proto.end(token);
+ }
}
boolean dumpLocked(FileDescriptor fd, PrintWriter pw, boolean needSep, String dumpPackage) {
@@ -272,12 +282,16 @@
return needSep;
}
- boolean isBadProcessLocked(final String processName, final int uid) {
- return mBadProcesses.get(processName, uid) != null;
+ boolean isBadProcess(final String processName, final int uid) {
+ synchronized (mBadProcesses) {
+ return mBadProcesses.get(processName, uid) != null;
+ }
}
- void clearBadProcessLocked(final String processName, final int uid) {
- mBadProcesses.remove(processName, uid);
+ void clearBadProcess(final String processName, final int uid) {
+ synchronized (mBadProcesses) {
+ mBadProcesses.remove(processName, uid);
+ }
}
void resetProcessCrashTimeLocked(final String processName, final int uid) {
@@ -747,8 +761,10 @@
if (!app.isolated) {
// XXX We don't have a way to mark isolated processes
// as bad, since they don't have a peristent identity.
- mBadProcesses.put(app.processName, app.uid,
- new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
+ synchronized (mBadProcesses) {
+ mBadProcesses.put(app.processName, app.uid,
+ new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
+ }
mProcessCrashTimes.remove(app.processName, app.uid);
}
app.bad = true;
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index d9fde0f..c5047e5 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 @@
@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 @@
}
/**
- * 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 @@
if (mUseFreezer && mFreezeHandler == null) {
Slog.d(TAG_AM, "Freezer enabled");
+ enableFreezer(true);
+
if (!mCachedAppOptimizerThread.isAlive()) {
mCachedAppOptimizerThread.start();
}
@@ -479,6 +540,8 @@
Process.setThreadGroupAndCpuset(mCachedAppOptimizerThread.getThreadId(),
Process.THREAD_GROUP_SYSTEM);
+ } else {
+ enableFreezer(false);
}
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 09ffbff..cd3e210 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2360,7 +2360,7 @@
if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
// If we are in the background, then check to see if this process
// is bad. If so, we will just silently fail.
- if (mService.mAppErrors.isBadProcessLocked(processName, info.uid)) {
+ if (mService.mAppErrors.isBadProcess(processName, info.uid)) {
if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
+ "/" + processName);
return null;
@@ -2373,11 +2373,11 @@
if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
+ "/" + processName);
mService.mAppErrors.resetProcessCrashTimeLocked(processName, info.uid);
- if (mService.mAppErrors.isBadProcessLocked(processName, info.uid)) {
+ if (mService.mAppErrors.isBadProcess(processName, info.uid)) {
EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
UserHandle.getUserId(info.uid), info.uid,
info.processName);
- mService.mAppErrors.clearBadProcessLocked(processName, info.uid);
+ mService.mAppErrors.clearBadProcess(processName, info.uid);
if (app != null) {
app.bad = false;
}
diff --git a/services/core/java/com/android/server/audio/AudioEventLogger.java b/services/core/java/com/android/server/audio/AudioEventLogger.java
index 9ebd75b..af0e978 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 @@
* @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 3f29eb5..4378490 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_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 @@
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 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 @@
mPrescaleAbsoluteVolume[i] = preScale[i];
}
}
+
+ // check on volume initialization
+ checkVolumeRangeInitialization("AudioService()");
}
public void systemReady() {
@@ -1015,11 +1024,15 @@
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 @@
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 @@
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 @@
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 @@
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 @@
//==========================================================================================
// 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 @@
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 9128359..4be596d 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 @@
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 dec40e3..e585b48 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 @@
// 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 7c8fb5a..1f0066a 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_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 @@
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 @@
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 @@
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 @@
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 0576e91..70ffaae 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 @@
@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/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index 5c30fe8..3e5b6e3 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -821,7 +821,7 @@
byte[] data = psdsDownloader.downloadPsdsData(psdsType);
if (data != null) {
if (DEBUG) Log.d(TAG, "calling native_inject_psds_data");
- native_inject_psds_data(data, data.length);
+ native_inject_psds_data(data, data.length, psdsType);
mPsdsBackOff.reset();
}
@@ -2111,7 +2111,7 @@
private native boolean native_supports_psds();
- private native void native_inject_psds_data(byte[] data, int length);
+ private native void native_inject_psds_data(byte[] data, int length, int psdsType);
// DEBUG Support
private native String native_get_internal_state();
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 29ee8eb..ded77b3 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -518,8 +518,9 @@
private final SparseBooleanArray mRestrictBackgroundAllowlistRevokedUids =
new SparseBooleanArray();
+ final Object mMeteredIfacesLock = new Object();
/** Set of ifaces that are metered. */
- @GuardedBy("mNetworkPoliciesSecondLock")
+ @GuardedBy("mMeteredIfacesLock")
private ArraySet<String> mMeteredIfaces = new ArraySet<>();
/** Set of over-limit templates that have been notified. */
@GuardedBy("mNetworkPoliciesSecondLock")
@@ -1972,13 +1973,15 @@
}
// Remove quota from any interfaces that are no longer metered.
- for (int i = mMeteredIfaces.size() - 1; i >= 0; i--) {
- final String iface = mMeteredIfaces.valueAt(i);
- if (!newMeteredIfaces.contains(iface)) {
- removeInterfaceQuotaAsync(iface);
+ synchronized (mMeteredIfacesLock) {
+ for (int i = mMeteredIfaces.size() - 1; i >= 0; i--) {
+ final String iface = mMeteredIfaces.valueAt(i);
+ if (!newMeteredIfaces.contains(iface)) {
+ removeInterfaceQuotaAsync(iface);
+ }
}
+ mMeteredIfaces = newMeteredIfaces;
}
- mMeteredIfaces = newMeteredIfaces;
final ContentResolver cr = mContext.getContentResolver();
final boolean quotaEnabled = Settings.Global.getInt(cr,
@@ -2030,7 +2033,10 @@
mSubscriptionOpportunisticQuota.put(subId, quotaBytes);
}
- final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
+ final String[] meteredIfaces;
+ synchronized (mMeteredIfacesLock) {
+ meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
+ }
mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget();
mHandler.obtainMessage(MSG_ADVISE_PERSIST_THRESHOLD, lowestRule).sendToTarget();
@@ -3436,7 +3442,10 @@
fout.print("Restrict background: "); fout.println(mRestrictBackground);
fout.print("Restrict power: "); fout.println(mRestrictPower);
fout.print("Device idle: "); fout.println(mDeviceIdleMode);
- fout.print("Metered ifaces: "); fout.println(mMeteredIfaces);
+ synchronized (mMeteredIfacesLock) {
+ fout.print("Metered ifaces: ");
+ fout.println(mMeteredIfaces);
+ }
fout.println();
fout.print("mRestrictBackgroundLowPowerMode: " + mRestrictBackgroundLowPowerMode);
@@ -4632,7 +4641,7 @@
}
case MSG_LIMIT_REACHED: {
final String iface = (String) msg.obj;
- synchronized (mNetworkPoliciesSecondLock) {
+ synchronized (mMeteredIfacesLock) {
// fast return if not needed.
if (!mMeteredIfaces.contains(iface)) {
return true;
@@ -5274,7 +5283,7 @@
isBackgroundRestricted = mRestrictBackground;
}
final boolean isNetworkMetered;
- synchronized (mNetworkPoliciesSecondLock) {
+ synchronized (mMeteredIfacesLock) {
isNetworkMetered = mMeteredIfaces.contains(ifname);
}
final boolean ret = isUidNetworkingBlockedInternal(uid, uidRules, isNetworkMetered,
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 3d7c978..f168ac7 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 @@
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 b6b7e93..c6269eb 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 @@
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 @@
.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 @@
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/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index e44c8ab..6ecaab6 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -407,6 +407,10 @@
@GuardedBy("mUsersLock")
private int[] mUserIds;
+
+ @GuardedBy("mUsersLock")
+ private int[] mUserIdsIncludingPreCreated;
+
@GuardedBy("mPackagesLock")
private int mNextSerialNumber;
private int mUserVersion = 0;
@@ -2496,16 +2500,35 @@
}
/**
- * Returns an array of user ids. This array is cached here for quick access, so do not modify or
- * cache it elsewhere.
+ * Returns an array of user ids.
+ *
+ * <p>This array is cached here for quick access, so do not modify or cache it elsewhere.
+ *
* @return the array of user ids.
*/
- public int[] getUserIds() {
+ public @NonNull int[] getUserIds() {
synchronized (mUsersLock) {
return mUserIds;
}
}
+ /**
+ * Returns an array of user ids, including pre-created users.
+ *
+ * <p>This method should only used for the specific cases that need to handle pre-created users;
+ * most callers should call {@link #getUserIds()} instead.
+ *
+ * <p>This array is cached here for quick access, so do not modify or
+ * cache it elsewhere.
+ *
+ * @return the array of user ids.
+ */
+ public @NonNull int[] getUserIdsIncludingPreCreated() {
+ synchronized (mUsersLock) {
+ return mUserIdsIncludingPreCreated;
+ }
+ }
+
@GuardedBy({"mRestrictionsLock", "mPackagesLock"})
private void readUserListLP() {
if (!mUserListFile.exists()) {
@@ -4361,23 +4384,43 @@
*/
private void updateUserIds() {
int num = 0;
+ int numIncludingPreCreated = 0;
synchronized (mUsersLock) {
final int userSize = mUsers.size();
for (int i = 0; i < userSize; i++) {
- UserInfo userInfo = mUsers.valueAt(i).info;
- if (!userInfo.partial && !userInfo.preCreated) {
- num++;
+ final UserInfo userInfo = mUsers.valueAt(i).info;
+ if (!userInfo.partial) {
+ numIncludingPreCreated++;
+ if (!userInfo.preCreated) {
+ num++;
+ }
}
}
+ if (DBG) {
+ Slog.d(LOG_TAG, "updateUserIds(): numberUsers= " + num
+ + " includingPreCreated=" + numIncludingPreCreated);
+ }
final int[] newUsers = new int[num];
+ final int[] newUsersIncludingPreCreated = new int[numIncludingPreCreated];
+
int n = 0;
+ int nIncludingPreCreated = 0;
for (int i = 0; i < userSize; i++) {
- UserInfo userInfo = mUsers.valueAt(i).info;
- if (!userInfo.partial && !userInfo.preCreated) {
- newUsers[n++] = mUsers.keyAt(i);
+ final UserInfo userInfo = mUsers.valueAt(i).info;
+ if (!userInfo.partial) {
+ final int userId = mUsers.keyAt(i);
+ newUsersIncludingPreCreated[nIncludingPreCreated++] = userId;
+ if (!userInfo.preCreated) {
+ newUsers[n++] = userId;
+ }
}
}
mUserIds = newUsers;
+ mUserIdsIncludingPreCreated = newUsersIncludingPreCreated;
+ if (DBG) {
+ Slog.d(LOG_TAG, "updateUserIds(): userIds= " + Arrays.toString(mUserIds)
+ + " includingPreCreated=" + Arrays.toString(mUserIdsIncludingPreCreated));
+ }
}
}
@@ -4841,6 +4884,8 @@
synchronized (mUsersLock) {
pw.print(" Cached user IDs: ");
pw.println(Arrays.toString(mUserIds));
+ pw.print(" Cached user IDs (including pre-created): ");
+ pw.println(Arrays.toString(mUserIdsIncludingPreCreated));
}
} // synchronized (mPackagesLock)
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 75a88e2..f7721a4 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 @@
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/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index f5dd918..ffdcc22 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -83,7 +83,6 @@
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
-import android.content.pm.UserInfo;
import android.content.pm.parsing.component.ParsedPermission;
import android.content.pm.parsing.component.ParsedPermissionGroup;
import android.content.pm.permission.SplitPermissionInfoParcelable;
@@ -121,7 +120,6 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import android.util.TimingsTraceLog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -3146,17 +3144,7 @@
* @return user ids for created users and pre-created users
*/
private int[] getAllUserIds() {
- final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
- t.traceBegin("getAllUserIds");
- List<UserInfo> users = UserManagerService.getInstance().getUsers(
- /*excludePartial=*/ true, /*excludeDying=*/ true, /*excludePreCreated=*/ false);
- int size = users.size();
- final int[] userIds = new int[size];
- for (int i = 0; i < size; i++) {
- userIds[i] = users.get(i).id;
- }
- t.traceEnd();
- return userIds;
+ return UserManagerService.getInstance().getUserIdsIncludingPreCreated();
}
/**
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Watchdog.java
index 8e5ecee..ebe9733 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 @@
* 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 c382e11..5a587cc 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.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 @@
} 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 @@
} 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 7d4d562..9f68d62 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1586,7 +1586,8 @@
hasBeenLaunched = false;
mStackSupervisor = supervisor;
- info.taskAffinity = getTaskAffinityWithUid(info.taskAffinity, info.applicationInfo.uid);
+ info.taskAffinity = computeTaskAffinity(info.taskAffinity, info.applicationInfo.uid,
+ launchMode);
taskAffinity = info.taskAffinity;
final String uid = Integer.toString(info.applicationInfo.uid);
if (info.windowLayout != null && info.windowLayout.windowLayoutAffinity != null
@@ -1647,17 +1648,18 @@
}
/**
- * Generate the task affinity with uid. For b/35954083, Limit task affinity to uid to avoid
- * issues associated with sharing affinity across uids.
+ * Generate the task affinity with uid and activity launch mode. For b/35954083, Limit task
+ * affinity to uid to avoid issues associated with sharing affinity across uids.
*
* @param affinity The affinity of the activity.
* @param uid The user-ID that has been assigned to this application.
- * @return The task affinity with uid.
+ * @param launchMode The activity launch mode
+ * @return The task affinity
*/
- static String getTaskAffinityWithUid(String affinity, int uid) {
+ static String computeTaskAffinity(String affinity, int uid, int launchMode) {
final String uidStr = Integer.toString(uid);
if (affinity != null && !affinity.startsWith(uidStr)) {
- affinity = uidStr + ":" + affinity;
+ affinity = uidStr + (launchMode == LAUNCH_SINGLE_INSTANCE ? "-si:" : ":") + affinity;
}
return affinity;
}
@@ -2122,11 +2124,6 @@
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 +2383,10 @@
}
}
- 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 +2663,7 @@
}
private void prepareActivityHideTransitionAnimation(int transit) {
- final DisplayContent dc = getDisplay().mDisplayContent;
+ final DisplayContent dc = mDisplayContent;
dc.prepareAppTransition(transit, false);
setVisibility(false);
dc.executeAppTransition();
@@ -2708,7 +2708,7 @@
}
if (ensureVisibility) {
- getDisplay().ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
+ mDisplayContent.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
false /* preserveWindows */, true /* notifyClients */);
}
}
@@ -4652,7 +4652,7 @@
}
// 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 +4931,8 @@
}
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 +6830,7 @@
onMergedOverrideConfigurationChanged();
}
- final DisplayContent display = getDisplay();
+ final DisplayContent display = mDisplayContent;
if (display == null) {
return;
}
@@ -7259,7 +7255,7 @@
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
lifecycleItem = ResumeActivityItem.obtain(
- getDisplay().mDisplayContent.isNextTransitionForward());
+ mDisplayContent.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
@@ -7584,11 +7580,7 @@
* 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 34f7f79..9df192b7 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 @@
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 f206259..19755f2 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 @@
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 @@
// 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 c58b5b5..505233c 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 @@
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 @@
} 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 @@
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 @@
}
final long origId = Binder.clearCallingIdentity();
try {
- display.mDisplayContent.registerRemoteAnimations(definition);
+ display.registerRemoteAnimations(definition);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -5466,7 +5466,7 @@
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 @@
// 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 c36a75b..69e8c57 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 @@
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 @@
if (isKeyguardLocked()) {
mService.deferWindowLayout();
try {
- mRootWindowContainer.getDefaultDisplay().mDisplayContent
+ mRootWindowContainer.getDefaultDisplay()
.prepareAppTransition(resolveOccludeTransit(),
false /* alwaysKeepCurrent */, 0 /* flags */,
true /* forceOverride */);
@@ -344,8 +344,7 @@
// 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 @@
}
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 @@
}
// 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 c8d7693..c496901 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 @@
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 3c64ffb..255b3f1 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 @@
// 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 6182a55..6539e13 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_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.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 @@
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 bfaaf46..70fd860 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 @@
taskDisplayArea.onStackWindowingModeChanged(this);
}
- final DisplayContent display = getDisplay();
- if (display == null ) {
+ if (mDisplayContent == null) {
return;
}
@@ -2336,7 +2335,7 @@
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 @@
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 @@
}
}
- @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 @@
!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 @@
* otherwise.
*/
boolean isFocusedStackOnDisplay() {
- final DisplayContent display = getDisplay();
- return display != null && this == display.getFocusedStack();
+ return mDisplayContent != null && this == mDisplayContent.getFocusedStack();
}
/**
@@ -5760,7 +5742,7 @@
* {@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 @@
// 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 @@
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 @@
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 @@
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 */);
@@ -6655,7 +6637,8 @@
// Basic case: for simple app-centric recents, we need to recreate
// the task if the affinity has changed.
- final String affinity = ActivityRecord.getTaskAffinityWithUid(destAffinity, srec.getUid());
+ final String affinity = ActivityRecord.computeTaskAffinity(destAffinity, srec.getUid(),
+ srec.launchMode);
if (srec == null || srec.getTask().affinity == null
|| !srec.getTask().affinity.equals(affinity)) {
return true;
@@ -6807,7 +6790,7 @@
ActivityOptions.abort(options);
}
}
- getDisplay().mDisplayContent.prepareAppTransition(transit, false,
+ mDisplayContent.prepareAppTransition(transit, false,
0 /* flags */, forceOverride);
}
@@ -6855,7 +6838,7 @@
// 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 +6862,7 @@
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 +6892,7 @@
mAtmService.getTaskChangeNotificationController()
.notifyTaskMovedToFront(tr.getTaskInfo());
} finally {
- getDisplay().continueUpdateImeTarget();
+ mDisplayContent.continueUpdateImeTarget();
}
}
@@ -6959,7 +6942,7 @@
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 +6951,7 @@
}
mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */,
- getDisplay().mDisplayId, false /* markFrozenIfConfigChanged */,
+ mDisplayContent.mDisplayId, false /* markFrozenIfConfigChanged */,
false /* deferResume */);
ActivityRecord topActivity = getDisplayArea().topRunningActivity();
@@ -6976,7 +6959,7 @@
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 +7558,12 @@
}
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 c5ebace..8bf0820 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 @@
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 @@
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 4b5f38c..d84f9d1 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -97,6 +97,7 @@
"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 6a6da0e..7e9e11d 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_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 9751c46..5dd6cd7 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 @@
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 @@
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 @@
ScopedUtfChars filenameChars(env, filenameObj.get());
ScopedUtfChars contentsChars(env, contentsObj.get());
- KeyCharacterMap::loadContents(filenameChars.c_str(),
- contentsChars.c_str(), KeyCharacterMap::FORMAT_OVERLAY, &result);
+ base::Result<std::shared_ptr<KeyCharacterMap>> ret =
+ KeyCharacterMap::loadContents(filenameChars.c_str(), contentsChars.c_str(),
+ KeyCharacterMap::FORMAT_OVERLAY);
+ if (ret) {
+ result = *ret;
+ }
}
checkAndClearExceptionFromCallback(env, "getKeyboardLayoutOverlay");
return result;
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 777cbf4..4e53aa2 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -928,7 +928,7 @@
* GnssPsdsCallback class implements the callback methods for the IGnssPsds
* interface.
*/
-class GnssPsdsCallback : public IGnssPsdsCallback {
+struct GnssPsdsCallback : public IGnssPsdsCallback {
Return<void> downloadRequestCb() override;
Return<void> downloadRequestCb_3_0(int32_t psdsType) override;
};
@@ -2743,19 +2743,26 @@
static jboolean android_location_GnssLocationProvider_supports_psds(
JNIEnv* /* env */, jobject /* obj */) {
- return (gnssXtraIface != nullptr) ? JNI_TRUE : JNI_FALSE;
+ return (gnssPsdsIface != nullptr || gnssXtraIface != nullptr) ? JNI_TRUE : JNI_FALSE;
}
static void android_location_GnssLocationProvider_inject_psds_data(JNIEnv* env, jobject /* obj */,
- jbyteArray data, jint length) {
- if (gnssXtraIface == nullptr) {
- ALOGE("%s: IGnssXtra interface not available.", __func__);
+ jbyteArray data, jint length,
+ jint psdsType) {
+ if (gnssPsdsIface == nullptr && gnssXtraIface == nullptr) {
+ ALOGE("%s: IGnssPsds or IGnssXtra interface not available.", __func__);
return;
}
jbyte* bytes = reinterpret_cast<jbyte *>(env->GetPrimitiveArrayCritical(data, 0));
- auto result = gnssXtraIface->injectXtraData(std::string((const char*)bytes, length));
- checkHidlReturn(result, "IGnssXtra injectXtraData() failed.");
+ if (gnssPsdsIface != nullptr) {
+ auto result = gnssPsdsIface->injectPsdsData_3_0(psdsType,
+ std::string((const char*)bytes, length));
+ checkHidlReturn(result, "IGnssPsds injectPsdsData() failed.");
+ } else if (gnssXtraIface != nullptr) {
+ auto result = gnssXtraIface->injectXtraData(std::string((const char*)bytes, length));
+ checkHidlReturn(result, "IGnssXtra injectXtraData() failed.");
+ }
env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
}
@@ -3685,7 +3692,7 @@
reinterpret_cast<void*>(android_location_GnssLocationProvider_inject_location)},
{"native_supports_psds", "()Z",
reinterpret_cast<void*>(android_location_GnssLocationProvider_supports_psds)},
- {"native_inject_psds_data", "([BI)V",
+ {"native_inject_psds_data", "([BII)V",
reinterpret_cast<void*>(android_location_GnssLocationProvider_inject_psds_data)},
{"native_agps_set_id", "(ILjava/lang/String;)V",
reinterpret_cast<void*>(android_location_GnssLocationProvider_agps_set_id)},
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index b2512d3..eec7d12 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,26 @@
}
@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);
+ simulateAddBasicAndroid(appsFilter);
+ appsFilter.onSystemReady();
+
+ PackageSetting target = simulateAddPackage(appsFilter,
+ 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);
+
+ assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+ SYSTEM_USER));
+ }
+
+
+ @Test
+ public void testForceQueryable_NonSystemFilters() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor);
@@ -391,7 +410,7 @@
PackageSetting calling = simulateAddPackage(appsFilter,
pkg("com.some.other.package"), DUMMY_CALLING_APPID);
- assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
+ assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
SYSTEM_USER));
}
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 59f0a79..bca990c 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 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 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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 4cad397..524f32d 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 @@
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 e5c9ecc..e537b7c 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 @@
.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/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 54c7f27..9954f48 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -28,6 +28,8 @@
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -447,6 +449,31 @@
}
@Test
+ public void testRemoveAffinityTask() {
+ // Add task to recents
+ final String taskAffinity = "affinity";
+ final int uid = 10123;
+ final Task task1 = createTaskBuilder(".Task1").setStack(mStack).build();
+ task1.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid, LAUNCH_MULTIPLE);
+ mRecentTasks.add(task1);
+
+ // Add another task to recents, and make sure the previous task was removed.
+ final Task task2 = createTaskBuilder(".Task2").setStack(mStack).build();
+ task2.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid, LAUNCH_MULTIPLE);
+ mRecentTasks.add(task2);
+ assertEquals(1, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
+ true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().size());
+
+ // Add another single-instance task to recents, and make sure no task is removed.
+ final Task task3 = createTaskBuilder(".Task3").setStack(mStack).build();
+ task3.affinity = ActivityRecord.computeTaskAffinity(taskAffinity, uid,
+ LAUNCH_SINGLE_INSTANCE);
+ mRecentTasks.add(task3);
+ assertEquals(2, mRecentTasks.getRecentTasks(MAX_VALUE, 0 /* flags */,
+ true /* getTasksAllowed */, TEST_USER_0_ID, 0).getList().size());
+ }
+
+ @Test
public void testAddTasksHomeClearUntrackedTasks_expectFinish() {
// There may be multiple tasks with the same base intent by flags (FLAG_ACTIVITY_NEW_TASK |
// FLAG_ACTIVITY_MULTIPLE_TASK). If the previous task is still active, it should be removed
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 982e469..6c648a8 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 @@
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 @@
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 @@
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 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 @@
});
// 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 @@
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/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 952997e..943d783 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -18,7 +18,7 @@
name: "FlickerTests",
srcs: ["src/**/*.java", "src/**/*.kt"],
manifest: "AndroidManifest.xml",
- test_config: "AndroidTest.xml",
+ test_config: "AndroidTestPhysicalDevices.xml",
platform_apis: true,
certificate: "platform",
test_suites: ["device-tests"],
@@ -33,3 +33,24 @@
"launcher-aosp-tapl"
],
}
+
+
+android_test {
+ name: "FlickerTestsVirtual",
+ srcs: ["src/**/*.java", "src/**/*.kt"],
+ manifest: "AndroidManifest.xml",
+ test_config: "AndroidTestVirtualDevices.xml",
+ platform_apis: true,
+ certificate: "platform",
+ test_suites: ["device-tests"],
+ libs: ["android.test.runner"],
+ static_libs: [
+ "androidx.test.ext.junit",
+ "flickertestapplib",
+ "flickerlib",
+ "truth-prebuilt",
+ "app-helpers-core",
+ "launcher-helper-lib",
+ "launcher-aosp-tapl"
+ ],
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTestPhysicalDevices.xml
similarity index 95%
copy from tests/FlickerTests/AndroidTest.xml
copy to tests/FlickerTests/AndroidTestPhysicalDevices.xml
index 68c99a3..1650438 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTestPhysicalDevices.xml
@@ -27,6 +27,7 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.server.wm.flicker"/>
+ <option name="include-annotation" value="androidx.test.filters.RequiresDevice" />
<option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
<option name="shell-timeout" value="6600s" />
<option name="test-timeout" value="6000s" />
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTestVirtualDevices.xml
similarity index 95%
rename from tests/FlickerTests/AndroidTest.xml
rename to tests/FlickerTests/AndroidTestVirtualDevices.xml
index 68c99a3..222212a 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTestVirtualDevices.xml
@@ -27,6 +27,7 @@
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.server.wm.flicker"/>
+ <option name="exclude-annotation" value="androidx.test.filters.RequiresDevice" />
<option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
<option name="shell-timeout" value="6600s" />
<option name="test-timeout" value="6000s" />
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index 80d0394..404c789 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -39,7 +39,7 @@
* Test IME window closing back to app window transitions.
* To run this test: `atest FlickerTests:CloseImeWindowToAppTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class CloseImeAutoOpenWindowToAppTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index c0658fe..b64811b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -39,7 +39,7 @@
* Test IME window closing back to app window transitions.
* To run this test: `atest FlickerTests:CloseImeWindowToAppTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class CloseImeAutoOpenWindowToHomeTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index 67c46d3..0940c19 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.NonRotationTestBase
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -39,7 +39,7 @@
* Test IME window closing back to app window transitions.
* To run this test: `atest FlickerTests:CloseImeWindowToAppTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
open class CloseImeWindowToAppTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index dcf3085..c2e87db 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.NonRotationTestBase
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -40,7 +40,7 @@
* Test IME window closing to home transitions.
* To run this test: `atest FlickerTests:CloseImeWindowToHomeTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
open class CloseImeWindowToHomeTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index 5874a07..11ccb69 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.ime
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.NonRotationTestBase
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -39,7 +39,7 @@
* Test IME window opening transitions.
* To run this test: `atest FlickerTests:OpenImeWindowTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenImeWindowTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 62337e9..254209a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.launch
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
@@ -38,7 +38,7 @@
* Test cold launch app from launcher.
* To run this test: `atest FlickerTests:OpenAppColdTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenAppColdTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 57d6127..dda41a3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.launch
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.StandardAppHelper
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.focusChanges
@@ -39,7 +39,7 @@
* Test warm launch app.
* To run this test: `atest FlickerTests:OpenAppWarmTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenAppWarmTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt
index 4acd975..9cfc033 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/EnterPipTest.kt
@@ -18,7 +18,7 @@
import android.view.Surface
import androidx.test.filters.FlakyTest
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.closePipWindow
import com.android.server.wm.flicker.helpers.expandPipWindow
@@ -41,7 +41,7 @@
* Test Pip launch.
* To run this test: `atest FlickerTests:PipToAppTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 152738416)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
index 04c2f59..deccc90 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
@@ -18,7 +18,7 @@
import android.view.Surface
import androidx.test.filters.FlakyTest
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.helpers.closePipWindow
@@ -42,7 +42,7 @@
* Test Pip launch.
* To run this test: `atest FlickerTests:PipToAppTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 152738416)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
index b6074cd..f40869c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
@@ -18,7 +18,7 @@
import android.view.Surface
import androidx.test.filters.FlakyTest
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.focusChanges
import com.android.server.wm.flicker.helpers.closePipWindow
@@ -41,7 +41,7 @@
* Test Pip launch.
* To run this test: `atest FlickerTests:PipToHomeTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 152738416)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 5e75e4a..0ca1508 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -16,8 +16,8 @@
package com.android.server.wm.flicker.rotation
+import androidx.test.filters.RequiresDevice
import android.view.Surface
-import androidx.test.filters.LargeTest
import com.android.server.wm.flicker.NonRotationTestBase.Companion.SCREENSHOT_LAYER
import com.android.server.wm.flicker.RotationTestBase
import com.android.server.wm.flicker.StandardAppHelper
@@ -42,7 +42,7 @@
* Cycle through supported app rotations.
* To run this test: `atest FlickerTest:ChangeAppRotationTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class ChangeAppRotationTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index de87b41..33a823d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -20,14 +20,13 @@
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.view.Surface
import androidx.test.filters.FlakyTest
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.RotationTestBase
import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.focusDoesNotChange
import com.android.server.wm.flicker.helpers.WindowUtils
-import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.stopPackage
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
@@ -48,7 +47,7 @@
* Cycle through supported app rotations using seamless rotations.
* To run this test: `atest FlickerTests:SeamlessAppRotationTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 147659548)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
index 279092d..c5e48d9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.splitscreen
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.NonRotationTestBase
import com.android.server.wm.flicker.StandardAppHelper
import com.android.server.wm.flicker.dsl.flicker
@@ -43,7 +43,7 @@
* Test open app to split screen.
* To run this test: `atest FlickerTests:OpenAppToSplitScreenTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenAppToSplitScreenTest(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
index a08b2bf..91211ca 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
@@ -21,7 +21,7 @@
import android.view.Surface
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.FlakyTest
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import androidx.test.uiautomator.By
import com.android.server.wm.flicker.FlickerTestBase
import com.android.server.wm.flicker.StandardAppHelper
@@ -52,7 +52,7 @@
*
* Currently it runs only in 0 degrees because of b/156100803
*/
-@LargeTest
+@RequiresDevice
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 159096424)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
index e2d7839..5c7dcd9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
@@ -17,7 +17,7 @@
package com.android.server.wm.flicker.splitscreen
import android.view.Surface
-import androidx.test.filters.LargeTest
+import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.NonRotationTestBase
import com.android.server.wm.flicker.StandardAppHelper
import com.android.server.wm.flicker.dsl.flicker
@@ -43,7 +43,7 @@
* Test open app to split screen.
* To run this test: `atest FlickerTests:SplitScreenToLauncherTest`
*/
-@LargeTest
+@RequiresDevice
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class SplitScreenToLauncherTest(
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index bcb5c99..1f23bf3 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.SparseArray;
import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -4028,7 +4027,6 @@
}
@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 5ac9dfd..0aca13e 100644
--- a/tools/validatekeymaps/Main.cpp
+++ b/tools/validatekeymaps/Main.cpp
@@ -96,21 +96,19 @@
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 ee7320f..b104dec 100644
--- a/wifi/api/current.txt
+++ b/wifi/api/current.txt
@@ -507,6 +507,7 @@
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 a3c4ae7..e4e900f 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -149,6 +149,11 @@
*/
private boolean mIsNetworkUntrusted;
+ /**
+ * Whether this network will use enhanced MAC randomization.
+ */
+ private boolean mIsEnhancedMacRandomizationEnabled;
+
public Builder() {
mSsid = null;
mBssid = null;
@@ -171,6 +176,7 @@
mWapiEnterpriseConfig = null;
mIsNetworkUntrusted = false;
mPriorityGroup = 0;
+ mIsEnhancedMacRandomizationEnabled = true;
}
/**
@@ -394,6 +400,29 @@
}
/**
+ * 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 @@
wifiConfiguration.meteredOverride = mMeteredOverride;
wifiConfiguration.carrierId = mCarrierId;
wifiConfiguration.trusted = !mIsNetworkUntrusted;
+ wifiConfiguration.macRandomizationSetting = mIsEnhancedMacRandomizationEnabled
+ ? WifiConfiguration.RANDOMIZATION_ENHANCED
+ : WifiConfiguration.RANDOMIZATION_PERSISTENT;
return wifiConfiguration;
}
@@ -607,6 +639,9 @@
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 3744a51..7d5a452 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -610,6 +610,33 @@
}
/**
+ * 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