diff options
112 files changed, 1108 insertions, 1620 deletions
diff --git a/apex/Android.bp b/apex/Android.bp index 410e21141f86..d6d3c27dcd6b 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -101,20 +101,13 @@ java_defaults { annotations_enabled: true, - stubs_library_visibility: [ - "//visibility:public", - ], - - // Set the visibility of the modules creating the stubs source. - stubs_source_visibility: [ - // Ignore any visibility rules specified on the java_sdk_library when - // setting the visibility of the stubs source modules. - "//visibility:override", + // Allow access to the stubs from anywhere + visibility: ["//visibility:public"], + stubs_library_visibility: ["//visibility:public"], - // Currently, the stub source is not required for anything other than building - // the stubs library so is private to avoid misuse. - "//visibility:private", - ], + // Hide impl library and stub sources + impl_library_visibility: [":__package__"], + stubs_source_visibility: ["//visibility:private"], // Collates API usages from each module for further analysis. plugins: ["java_api_finder"], diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt index 8186c9c69991..73511c0f5b87 100644 --- a/api/module-lib-current.txt +++ b/api/module-lib-current.txt @@ -42,6 +42,10 @@ package android.media { package android.media.session { + public static final class MediaController.PlaybackInfo implements android.os.Parcelable { + ctor public MediaController.PlaybackInfo(int, int, @IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.media.AudioAttributes, @Nullable String); + } + public final class MediaSession { field public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 65536; // 0x10000 } diff --git a/api/system-current.txt b/api/system-current.txt index 8009d0370dd8..c3e56643a805 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4199,10 +4199,8 @@ package android.media { public class AudioManager { method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDeviceForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener) throws java.lang.SecurityException; - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForCapturePresetChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener) throws java.lang.SecurityException; method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener) throws java.lang.SecurityException; method public void clearAudioServerStateCallback(); - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean clearPreferredDevicesForCapturePreset(int); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); method @IntRange(from=0) public long getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioProductStrategy> getAudioProductStrategies(); @@ -4213,7 +4211,6 @@ package android.media { method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioDeviceAttributes getPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); - method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getPreferredDevicesForCapturePreset(int); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int[] getSupportedSystemUsages(); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); @@ -4222,7 +4219,6 @@ package android.media { method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); method public void registerVolumeGroupCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.VolumeGroupCallback); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDeviceForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener); - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForCapturePresetChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean removePreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException; @@ -4232,7 +4228,6 @@ package android.media { method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForCapturePreset(int, @NonNull android.media.AudioDeviceAttributes); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setSupportedSystemUsages(@NonNull int[]); @@ -4262,10 +4257,6 @@ package android.media { method @Deprecated public void onPreferredDeviceForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @Nullable android.media.AudioDeviceAttributes); } - public static interface AudioManager.OnPreferredDevicesForCapturePresetChangedListener { - method public void onPreferredDevicesForCapturePresetChanged(int, @NonNull java.util.List<android.media.AudioDeviceAttributes>); - } - public static interface AudioManager.OnPreferredDevicesForStrategyChangedListener { method public void onPreferredDevicesForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>); } diff --git a/api/test-current.txt b/api/test-current.txt index af70562839ba..1aa3db6963b7 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -5621,18 +5621,18 @@ package android.window { public class TaskOrganizer extends android.window.WindowOrganizer { ctor public TaskOrganizer(); - method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static android.app.ActivityManager.RunningTaskInfo createRootTask(int, int); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static boolean deleteRootTask(@NonNull android.window.WindowContainerToken); - method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static java.util.List<android.app.ActivityManager.RunningTaskInfo> getChildTasks(@NonNull android.window.WindowContainerToken, @NonNull int[]); - method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static android.window.WindowContainerToken getImeTarget(int); - method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static java.util.List<android.app.ActivityManager.RunningTaskInfo> getRootTasks(int, @NonNull int[]); + method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public android.app.ActivityManager.RunningTaskInfo createRootTask(int, int); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public boolean deleteRootTask(@NonNull android.window.WindowContainerToken); + method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public java.util.List<android.app.ActivityManager.RunningTaskInfo> getChildTasks(@NonNull android.window.WindowContainerToken, @NonNull int[]); + method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public android.window.WindowContainerToken getImeTarget(int); + method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public java.util.List<android.app.ActivityManager.RunningTaskInfo> getRootTasks(int, @NonNull int[]); method @BinderThread public void onBackPressedOnTaskRoot(@NonNull android.app.ActivityManager.RunningTaskInfo); method @BinderThread public void onTaskAppeared(@NonNull android.app.ActivityManager.RunningTaskInfo, @NonNull android.view.SurfaceControl); method @BinderThread public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo); method @BinderThread public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo); method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void registerOrganizer(); method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setInterceptBackPressedOnTaskRoot(@NonNull android.window.WindowContainerToken, boolean); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static void setLaunchRoot(int, @NonNull android.window.WindowContainerToken); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setLaunchRoot(int, @NonNull android.window.WindowContainerToken); method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void unregisterOrganizer(); } @@ -5669,7 +5669,7 @@ package android.window { public class WindowOrganizer { ctor public WindowOrganizer(); method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public int applySyncTransaction(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.WindowContainerTransactionCallback); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static void applyTransaction(@NonNull android.window.WindowContainerTransaction); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void applyTransaction(@NonNull android.window.WindowContainerTransaction); } } diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp index 1e200c52a207..437a87e8df54 100644 --- a/cmds/hid/jni/com_android_commands_hid_Device.cpp +++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp @@ -27,9 +27,9 @@ #include <cstring> #include <memory> -#include <android/log.h> #include <android/looper.h> #include <jni.h> +#include <log/log.h> #include <nativehelper/JNIHelp.h> #include <nativehelper/ScopedLocalRef.h> #include <nativehelper/ScopedPrimitiveArray.h> @@ -37,10 +37,8 @@ #include <android-base/stringprintf.h> -#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) -#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) -#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) -#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) +// Log debug messages about the output. +static constexpr bool DEBUG_OUTPUT = false; namespace android { namespace uhid { @@ -61,7 +59,7 @@ static int handleLooperEvents(int /* fd */, int events, void* data) { static void checkAndClearException(JNIEnv* env, const char* methodName) { if (env->ExceptionCheck()) { - LOGE("An exception was thrown by callback '%s'.", methodName); + ALOGE("An exception was thrown by callback '%s'.", methodName); env->ExceptionClear(); } } @@ -115,9 +113,9 @@ void DeviceCallback::onDeviceGetReport(uint32_t requestId, uint8_t reportId) { checkAndClearException(env, "onDeviceGetReport"); } -void DeviceCallback::onDeviceOutput(const std::vector<uint8_t>& data) { +void DeviceCallback::onDeviceOutput(uint8_t rType, const std::vector<uint8_t>& data) { JNIEnv* env = getJNIEnv(); - env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOutput, + env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOutput, rType, toJbyteArray(env, data).get()); checkAndClearException(env, "onDeviceOutput"); } @@ -133,13 +131,13 @@ std::unique_ptr<Device> Device::open(int32_t id, const char* name, int32_t vid, std::unique_ptr<DeviceCallback> callback) { size_t size = descriptor.size(); if (size > HID_MAX_DESCRIPTOR_SIZE) { - LOGE("Received invalid hid report with descriptor size %zu, skipping", size); + ALOGE("Received invalid hid report with descriptor size %zu, skipping", size); return nullptr; } android::base::unique_fd fd(::open(UHID_PATH, O_RDWR | O_CLOEXEC)); if (!fd.ok()) { - LOGE("Failed to open uhid: %s", strerror(errno)); + ALOGE("Failed to open uhid: %s", strerror(errno)); return nullptr; } @@ -159,14 +157,14 @@ std::unique_ptr<Device> Device::open(int32_t id, const char* name, int32_t vid, errno = 0; ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev))); if (ret < 0 || ret != sizeof(ev)) { - LOGE("Failed to create uhid node: %s", strerror(errno)); + ALOGE("Failed to create uhid node: %s", strerror(errno)); return nullptr; } // Wait for the device to actually be created. ret = TEMP_FAILURE_RETRY(::read(fd, &ev, sizeof(ev))); if (ret < 0 || ev.type != UHID_START) { - LOGE("uhid node failed to start: %s", strerror(errno)); + ALOGE("uhid node failed to start: %s", strerror(errno)); return nullptr; } // using 'new' to access non-public constructor @@ -177,7 +175,7 @@ Device::Device(int32_t id, android::base::unique_fd fd, std::unique_ptr<DeviceCa : mId(id), mFd(std::move(fd)), mDeviceCallback(std::move(callback)) { ALooper* aLooper = ALooper_forThread(); if (aLooper == NULL) { - LOGE("Could not get ALooper, ALooper_forThread returned NULL"); + ALOGE("Could not get ALooper, ALooper_forThread returned NULL"); aLooper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); } ALooper_addFd(aLooper, mFd, 0, ALOOPER_EVENT_INPUT, handleLooperEvents, @@ -189,7 +187,7 @@ Device::~Device() { if (looper != NULL) { ALooper_removeFd(looper, mFd); } else { - LOGE("Could not remove fd, ALooper_forThread() returned NULL!"); + ALOGE("Could not remove fd, ALooper_forThread() returned NULL!"); } struct uhid_event ev = {}; ev.type = UHID_DESTROY; @@ -200,13 +198,13 @@ Device::~Device() { static void writeEvent(int fd, struct uhid_event& ev, const char* messageType) { ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev))); if (ret < 0 || ret != sizeof(ev)) { - LOGE("Failed to send uhid_event %s: %s", messageType, strerror(errno)); + ALOGE("Failed to send uhid_event %s: %s", messageType, strerror(errno)); } } void Device::sendReport(const std::vector<uint8_t>& report) const { if (report.size() > UHID_DATA_MAX) { - LOGE("Received invalid report of size %zu, skipping", report.size()); + ALOGE("Received invalid report of size %zu, skipping", report.size()); return; } @@ -230,14 +228,14 @@ void Device::sendGetFeatureReportReply(uint32_t id, const std::vector<uint8_t>& int Device::handleEvents(int events) { if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) { - LOGE("uhid node was closed or an error occurred. events=0x%x", events); + ALOGE("uhid node was closed or an error occurred. events=0x%x", events); mDeviceCallback->onDeviceError(); return 0; } struct uhid_event ev; ssize_t ret = TEMP_FAILURE_RETRY(::read(mFd, &ev, sizeof(ev))); if (ret < 0) { - LOGE("Failed to read from uhid node: %s", strerror(errno)); + ALOGE("Failed to read from uhid node: %s", strerror(errno)); mDeviceCallback->onDeviceError(); return 0; } @@ -254,23 +252,28 @@ int Device::handleEvents(int events) { case UHID_SET_REPORT: { const struct uhid_set_report_req& set_report = ev.u.set_report; if (set_report.size > UHID_DATA_MAX) { - LOGE("SET_REPORT contains too much data: size = %" PRIu16, set_report.size); + ALOGE("SET_REPORT contains too much data: size = %" PRIu16, set_report.size); return 0; } std::vector<uint8_t> data(set_report.data, set_report.data + set_report.size); - LOGI("Received SET_REPORT: id=%" PRIu32 " rnum=%" PRIu8 " data=%s", set_report.id, - set_report.rnum, toString(data).c_str()); + if (DEBUG_OUTPUT) { + ALOGD("Received SET_REPORT: id=%" PRIu32 " rnum=%" PRIu8 " data=%s", set_report.id, + set_report.rnum, toString(data).c_str()); + } break; } case UHID_OUTPUT: { struct uhid_output_req& output = ev.u.output; std::vector<uint8_t> data(output.data, output.data + output.size); - mDeviceCallback->onDeviceOutput(data); + if (DEBUG_OUTPUT) { + ALOGD("UHID_OUTPUT rtype=%" PRIu8 " data=%s", output.rtype, toString(data).c_str()); + } + mDeviceCallback->onDeviceOutput(output.rtype, data); break; } default: { - LOGI("Unhandled event type: %" PRIu32, ev.type); + ALOGI("Unhandled event type: %" PRIu32, ev.type); break; } } @@ -318,7 +321,7 @@ static void sendReport(JNIEnv* env, jclass /* clazz */, jlong ptr, jbyteArray ra if (d) { d->sendReport(report); } else { - LOGE("Could not send report, Device* is null!"); + ALOGE("Could not send report, Device* is null!"); } } @@ -329,7 +332,7 @@ static void sendGetFeatureReportReply(JNIEnv* env, jclass /* clazz */, jlong ptr std::vector<uint8_t> report = getData(env, rawReport); d->sendGetFeatureReportReply(id, report); } else { - LOGE("Could not send get feature report reply, Device* is null!"); + ALOGE("Could not send get feature report reply, Device* is null!"); } } @@ -354,7 +357,7 @@ static JNINativeMethod sMethods[] = { int register_com_android_commands_hid_Device(JNIEnv* env) { jclass clazz = env->FindClass("com/android/commands/hid/Device$DeviceCallback"); if (clazz == NULL) { - LOGE("Unable to find class 'DeviceCallback'"); + ALOGE("Unable to find class 'DeviceCallback'"); return JNI_ERR; } uhid::gDeviceCallbackClassInfo.onDeviceOpen = @@ -362,12 +365,12 @@ int register_com_android_commands_hid_Device(JNIEnv* env) { uhid::gDeviceCallbackClassInfo.onDeviceGetReport = env->GetMethodID(clazz, "onDeviceGetReport", "(II)V"); uhid::gDeviceCallbackClassInfo.onDeviceOutput = - env->GetMethodID(clazz, "onDeviceOutput", "([B)V"); + env->GetMethodID(clazz, "onDeviceOutput", "(B[B)V"); uhid::gDeviceCallbackClassInfo.onDeviceError = env->GetMethodID(clazz, "onDeviceError", "()V"); if (uhid::gDeviceCallbackClassInfo.onDeviceOpen == NULL || uhid::gDeviceCallbackClassInfo.onDeviceError == NULL) { - LOGE("Unable to obtain onDeviceOpen or onDeviceError methods"); + ALOGE("Unable to obtain onDeviceOpen or onDeviceError methods"); return JNI_ERR; } diff --git a/cmds/hid/jni/com_android_commands_hid_Device.h b/cmds/hid/jni/com_android_commands_hid_Device.h index 7202b45adcde..5483b40831a0 100644 --- a/cmds/hid/jni/com_android_commands_hid_Device.h +++ b/cmds/hid/jni/com_android_commands_hid_Device.h @@ -31,7 +31,7 @@ public: void onDeviceOpen(); void onDeviceGetReport(uint32_t requestId, uint8_t reportId); - void onDeviceOutput(const std::vector<uint8_t>& data); + void onDeviceOutput(uint8_t rType, const std::vector<uint8_t>& data); void onDeviceError(); private: diff --git a/cmds/hid/src/com/android/commands/hid/Device.java b/cmds/hid/src/com/android/commands/hid/Device.java index dade41511ae6..20b4bd86baec 100644 --- a/cmds/hid/src/com/android/commands/hid/Device.java +++ b/cmds/hid/src/com/android/commands/hid/Device.java @@ -26,6 +26,12 @@ import android.util.SparseArray; import com.android.internal.os.SomeArgs; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Map; @@ -38,12 +44,16 @@ public class Device { private static final int MSG_SEND_GET_FEATURE_REPORT_REPLY = 3; private static final int MSG_CLOSE_DEVICE = 4; + // Sync with linux uhid_event_type::UHID_OUTPUT + private static final byte UHID_EVENT_TYPE_UHID_OUTPUT = 6; + private final int mId; private final HandlerThread mThread; private final DeviceHandler mHandler; // mFeatureReports is limited to 256 entries, because the report number is 8-bit private final SparseArray<byte[]> mFeatureReports; private final Map<ByteBuffer, byte[]> mOutputs; + private final OutputStream mOutputStream; private long mTimeToSend; private final Object mCond = new Object(); @@ -66,6 +76,7 @@ public class Device { mHandler = new DeviceHandler(mThread.getLooper()); mFeatureReports = featureReports; mOutputs = outputs; + mOutputStream = System.out; SomeArgs args = SomeArgs.obtain(); args.argi1 = id; args.argi2 = vid; @@ -188,7 +199,27 @@ public class Device { } // native callback - public void onDeviceOutput(byte[] data) { + public void onDeviceOutput(byte rtype, byte[] data) { + JSONObject json = new JSONObject(); + try { + json.put("eventId", UHID_EVENT_TYPE_UHID_OUTPUT); + json.put("deviceId", mId); + json.put("reportType", rtype); + JSONArray dataArray = new JSONArray(); + for (int i = 0; i < data.length; i++) { + dataArray.put(data[i] & 0xFF); + } + json.put("reportData", dataArray); + } catch (JSONException e) { + throw new RuntimeException("Could not create JSON object ", e); + } + try { + mOutputStream.write(json.toString().getBytes()); + mOutputStream.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } + if (mOutputs == null) { Log.e(TAG, "Received OUTPUT request, but 'outputs' section is not found"); return; diff --git a/core/java/android/app/timezonedetector/TimeZoneConfiguration.java b/core/java/android/app/timezonedetector/TimeZoneConfiguration.java index 95db0a26cc6e..e879091cd68e 100644 --- a/core/java/android/app/timezonedetector/TimeZoneConfiguration.java +++ b/core/java/android/app/timezonedetector/TimeZoneConfiguration.java @@ -162,9 +162,9 @@ public final class TimeZoneConfiguration implements Parcelable { @Override public String toString() { - return "TimeZoneDetectorConfiguration{" + return "TimeZoneConfiguration{" + "mUserId=" + mUserId - + "mBundle=" + mBundle + + ", mBundle=" + mBundle + '}'; } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 0f1f276ce0f9..e108451b54fb 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -30,7 +30,6 @@ import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE; -import static android.content.pm.PackageManager.FEATURE_WATCH; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; @@ -159,8 +158,6 @@ public class PackageParser { SystemProperties.getBoolean(PROPERTY_CHILD_PACKAGES_ENABLED, false); public static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f; - public static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO = 1.333f; - public static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH = 1f; private static final int DEFAULT_MIN_SDK_VERSION = 1; private static final int DEFAULT_TARGET_SDK_VERSION = 0; @@ -4683,20 +4680,8 @@ public class PackageParser { * ratio set. */ private void setMinAspectRatio(Package owner) { - final float minAspectRatio; - if (owner.applicationInfo.minAspectRatio != 0) { - // Use the application max aspect ration as default if set. - minAspectRatio = owner.applicationInfo.minAspectRatio; - } else { - // Default to (1.33) 4:3 aspect ratio for pre-Q apps and unset for Q and greater. - // NOTE: 4:3 was the min aspect ratio Android devices can support pre-Q per the CDD, - // except for watches which always supported 1:1. - minAspectRatio = owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q - ? 0 - : (mCallback != null && mCallback.hasFeature(FEATURE_WATCH)) - ? DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH - : DEFAULT_PRE_Q_MIN_ASPECT_RATIO; - } + // Use the application max aspect ration as default if set. + final float minAspectRatio = owner.applicationInfo.minAspectRatio; for (Activity activity : owner.activities) { if (activity.hasMinAspectRatio()) { diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java index 4914601b0b5a..542cfc29f1a2 100644 --- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java +++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java @@ -67,7 +67,7 @@ public class ApkLiteParseUtils { * Automatically detects if the package is a monolithic style (single APK * file) or cluster style (directory of APKs). * <p> - * This performs sanity checking on cluster style packages, such as + * This performs validity checking on cluster style packages, such as * requiring identical package name and version codes, a single base APK, * and unique split names. * diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java index e1f08f3e55a1..d9857e0d2328 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java @@ -18,7 +18,6 @@ package android.content.pm.parsing; import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; -import static android.content.pm.PackageManager.FEATURE_WATCH; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED; @@ -211,7 +210,7 @@ public class ParsingPackageUtils { * package is a monolithic style (single APK file) or cluster style * (directory of APKs). * <p> - * This performs sanity checking on cluster style packages, such as + * This performs validity checking on cluster style packages, such as * requiring identical package name and version codes, a single base APK, * and unique split names. * <p> @@ -237,7 +236,7 @@ public class ParsingPackageUtils { /** * Parse all APKs contained in the given directory, treating them as a - * single package. This also performs sanity checking, such as requiring + * single package. This also performs validity checking, such as requiring * identical package name and version codes, a single base APK, and unique * split names. * <p> @@ -2375,21 +2374,8 @@ public class ParsingPackageUtils { * ratio set. */ private void setMinAspectRatio(ParsingPackage pkg) { - final float minAspectRatio; - float packageMinAspectRatio = pkg.getMinAspectRatio(); - if (packageMinAspectRatio != 0) { - // Use the application max aspect ration as default if set. - minAspectRatio = packageMinAspectRatio; - } else { - // Default to (1.33) 4:3 aspect ratio for pre-Q apps and unset for Q and greater. - // NOTE: 4:3 was the min aspect ratio Android devices can support pre-Q per the CDD, - // except for watches which always supported 1:1. - minAspectRatio = pkg.getTargetSdkVersion() >= Build.VERSION_CODES.Q - ? 0 - : (mCallback != null && mCallback.hasFeature(FEATURE_WATCH)) - ? PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH - : PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO; - } + // Use the application max aspect ration as default if set. + final float minAspectRatio = pkg.getMinAspectRatio(); List<ParsedActivity> activities = pkg.getActivities(); int activitiesSize = activities.size(); diff --git a/core/java/android/os/LocaleList.java b/core/java/android/os/LocaleList.java index ab4bb0b9f2cd..9c0bc45a346e 100644 --- a/core/java/android/os/LocaleList.java +++ b/core/java/android/os/LocaleList.java @@ -25,6 +25,7 @@ import android.icu.util.ULocale; import com.android.internal.annotations.GuardedBy; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; @@ -151,18 +152,18 @@ public final class LocaleList implements Parcelable { /** * Creates a new {@link LocaleList}. * + * If two or more same locales are passed, the repeated locales will be dropped. * <p>For empty lists of {@link Locale} items it is better to use {@link #getEmptyLocaleList()}, * which returns a pre-constructed empty list.</p> * * @throws NullPointerException if any of the input locales is <code>null</code>. - * @throws IllegalArgumentException if any of the input locales repeat. */ public LocaleList(@NonNull Locale... list) { if (list.length == 0) { mList = sEmptyList; mStringRepresentation = ""; } else { - final Locale[] localeList = new Locale[list.length]; + final ArrayList<Locale> localeList = new ArrayList<>(); final HashSet<Locale> seenLocales = new HashSet<Locale>(); final StringBuilder sb = new StringBuilder(); for (int i = 0; i < list.length; i++) { @@ -170,10 +171,10 @@ public final class LocaleList implements Parcelable { if (l == null) { throw new NullPointerException("list[" + i + "] is null"); } else if (seenLocales.contains(l)) { - throw new IllegalArgumentException("list[" + i + "] is a repetition"); + // Dropping duplicated locale entries. } else { final Locale localeClone = (Locale) l.clone(); - localeList[i] = localeClone; + localeList.add(localeClone); sb.append(localeClone.toLanguageTag()); if (i < list.length - 1) { sb.append(','); @@ -181,7 +182,7 @@ public final class LocaleList implements Parcelable { seenLocales.add(localeClone); } } - mList = localeList; + mList = localeList.toArray(new Locale[localeList.size()]); mStringRepresentation = sb.toString(); } } diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java index 69220722fc05..6ffd892e4351 100644 --- a/core/java/android/view/InsetsAnimationControlImpl.java +++ b/core/java/android/view/InsetsAnimationControlImpl.java @@ -16,6 +16,7 @@ package android.view; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.InsetsController.ANIMATION_TYPE_SHOW; import static android.view.InsetsController.AnimationType; import static android.view.InsetsController.DEBUG; @@ -24,6 +25,7 @@ import static android.view.InsetsState.ISIDE_LEFT; import static android.view.InsetsState.ISIDE_RIGHT; import static android.view.InsetsState.ISIDE_TOP; import static android.view.InsetsState.ITYPE_IME; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; @@ -308,8 +310,8 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll false /* isScreenRound */, false /* alwaysConsumeSystemBars */, null /* displayCutout */, LayoutParams.SOFT_INPUT_ADJUST_RESIZE /* legacySoftInputMode*/, - 0 /* legacyWindowFlags */, 0 /* legacySystemUiFlags */, typeSideMap) - .getInsets(mTypes); + 0 /* legacyWindowFlags */, 0 /* legacySystemUiFlags */, TYPE_APPLICATION, + WINDOWING_MODE_UNDEFINED, typeSideMap).getInsets(mTypes); } private Insets sanitize(Insets insets) { diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 403ac3ab29c0..92eade3affaa 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -500,9 +500,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation /** Pending control request that is waiting on IME to be ready to be shown */ private PendingControlRequest mPendingImeControlRequest; + private int mWindowType; private int mLastLegacySoftInputMode; private int mLastLegacyWindowFlags; private int mLastLegacySystemUiFlags; + private int mLastWindowingMode; private DisplayCutout mLastDisplayCutout; private boolean mStartingAnimation; private int mCaptionInsetsHeight = 0; @@ -571,7 +573,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation WindowInsets insets = state.calculateInsets(mFrame, mState /* ignoringVisibilityState*/, mLastInsets.isRound(), mLastInsets.shouldAlwaysConsumeSystemBars(), mLastDisplayCutout, mLastLegacySoftInputMode, mLastLegacyWindowFlags, - mLastLegacySystemUiFlags, null /* typeSideMap */); + mLastLegacySystemUiFlags, mWindowType, mLastWindowingMode, + null /* typeSideMap */); mHost.dispatchWindowInsetsAnimationProgress(insets, mUnmodifiableTmpRunningAnims); if (DEBUG) { for (WindowInsetsAnimation anim : mUnmodifiableTmpRunningAnims) { @@ -709,9 +712,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation * @see InsetsState#calculateInsets */ @VisibleForTesting - public WindowInsets calculateInsets(boolean isScreenRound, - boolean alwaysConsumeSystemBars, DisplayCutout cutout, + public WindowInsets calculateInsets(boolean isScreenRound, boolean alwaysConsumeSystemBars, + DisplayCutout cutout, int windowType, int windowingMode, int legacySoftInputMode, int legacyWindowFlags, int legacySystemUiFlags) { + mWindowType = windowType; + mLastWindowingMode = windowingMode; mLastLegacySoftInputMode = legacySoftInputMode; mLastLegacyWindowFlags = legacyWindowFlags; mLastLegacySystemUiFlags = legacySystemUiFlags; @@ -719,7 +724,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation mLastInsets = mState.calculateInsets(mFrame, null /* ignoringVisibilityState*/, isScreenRound, alwaysConsumeSystemBars, cutout, legacySoftInputMode, legacyWindowFlags, legacySystemUiFlags, - null /* typeSideMap */); + windowType, windowingMode, null /* typeSideMap */); return mLastInsets; } diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java index 700dc66fab55..ba40459692f7 100644 --- a/core/java/android/view/InsetsSourceConsumer.java +++ b/core/java/android/view/InsetsSourceConsumer.java @@ -113,13 +113,20 @@ public class InsetsSourceConsumer { InsetsState.typeToString(control.getType()), mController.getHost().getRootViewTitle())); } - // We are loosing control if (mSourceControl == null) { + // We are loosing control mController.notifyControlRevoked(this); - // Restore server visibility. - mState.getSource(getType()).setVisible( - mController.getLastDispatchedState().getSource(getType()).isVisible()); + // Check if we need to restore server visibility. + final InsetsSource source = mState.getSource(mType); + final boolean serverVisibility = + mController.getLastDispatchedState().getSourceOrDefaultVisibility(mType); + if (source.isVisible() != serverVisibility) { + source.setVisible(serverVisibility); + mController.notifyVisibilityChanged(); + } + + // For updateCompatSysUiVisibility applyLocalVisibilityOverride(); } else { // We are gaining control, and need to run an animation since previous state diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java index 593b37af26ad..373a0963dc2f 100644 --- a/core/java/android/view/InsetsState.java +++ b/core/java/android/view/InsetsState.java @@ -30,11 +30,15 @@ import static android.view.WindowInsets.Type.isVisibleInsetsType; import static android.view.WindowInsets.Type.statusBars; import static android.view.WindowInsets.Type.systemBars; import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; +import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; +import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import android.annotation.IntDef; import android.annotation.Nullable; +import android.app.WindowConfiguration; import android.graphics.Insets; import android.graphics.Rect; import android.os.Parcel; @@ -174,6 +178,7 @@ public class InsetsState implements Parcelable { public WindowInsets calculateInsets(Rect frame, @Nullable InsetsState ignoringVisibilityState, boolean isScreenRound, boolean alwaysConsumeSystemBars, DisplayCutout cutout, int legacySoftInputMode, int legacyWindowFlags, int legacySystemUiFlags, + int windowType, @WindowConfiguration.WindowingMode int windowingMode, @Nullable @InternalInsetsSide SparseIntArray typeSideMap) { Insets[] typeInsetsMap = new Insets[Type.SIZE]; Insets[] typeMaxInsetsMap = new Insets[Type.SIZE]; @@ -228,6 +233,9 @@ public class InsetsState implements Parcelable { if ((legacyWindowFlags & FLAG_FULLSCREEN) != 0) { compatInsetsTypes &= ~statusBars(); } + if (clearCompatInsets(windowType, legacyWindowFlags, windowingMode)) { + compatInsetsTypes = 0; + } return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, typeVisibilityMap, isScreenRound, alwaysConsumeSystemBars, cutout, compatInsetsTypes, @@ -449,6 +457,12 @@ public class InsetsState implements Parcelable { mSources[source.getType()] = source; } + public static boolean clearCompatInsets(int windowType, int windowFlags, int windowingMode) { + return (windowFlags & FLAG_LAYOUT_NO_LIMITS) != 0 + && windowType != TYPE_WALLPAPER && windowType != TYPE_SYSTEM_ERROR + && !WindowConfiguration.inMultiWindowMode(windowingMode); + } + public static @InternalInsetsType ArraySet<Integer> toInternalType(@InsetsType int types) { final ArraySet<Integer> result = new ArraySet<>(); if ((types & Type.STATUS_BARS) != 0) { diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 6a5074cb8696..f3a8d9754fd4 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -2253,9 +2253,11 @@ public final class ViewRootImpl implements ViewParent, /* package */ WindowInsets getWindowInsets(boolean forceConstruct) { if (mLastWindowInsets == null || forceConstruct) { + final Configuration config = mContext.getResources().getConfiguration(); mLastWindowInsets = mInsetsController.calculateInsets( - mContext.getResources().getConfiguration().isScreenRound(), - mAttachInfo.mAlwaysConsumeSystemBars, mPendingDisplayCutout.get(), + config.isScreenRound(), mAttachInfo.mAlwaysConsumeSystemBars, + mPendingDisplayCutout.get(), mWindowAttributes.type, + config.windowConfiguration.getWindowingMode(), mWindowAttributes.softInputMode, mWindowAttributes.flags, (mWindowAttributes.systemUiVisibility | mWindowAttributes.subtreeSystemUiVisibility)); diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java index 1a9003581078..e879bb4bff95 100644 --- a/core/java/android/view/WindowInsetsController.java +++ b/core/java/android/view/WindowInsetsController.java @@ -32,8 +32,6 @@ import java.lang.annotation.RetentionPolicy; /** * Interface to control windows that generate insets. - * - * TODO(118118435): Needs more information and examples once the API is more baked. */ public interface WindowInsetsController { diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index 27fbfb6d4d17..5d53ad7ef186 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -29,6 +29,7 @@ import android.annotation.UiContext; import android.app.ResourcesManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Insets; import android.graphics.Rect; import android.graphics.Region; @@ -271,13 +272,14 @@ public final class WindowManagerImpl implements WindowManager { final boolean alwaysConsumeSystemBars = WindowManagerGlobal.getWindowManagerService() .getWindowInsets(attrs, mContext.getDisplayId(), systemWindowInsets, stableInsets, displayCutout, insetsState); - final boolean isScreenRound = - mContext.getResources().getConfiguration().isScreenRound(); + final Configuration config = mContext.getResources().getConfiguration(); + final boolean isScreenRound = config.isScreenRound(); + final int windowingMode = config.windowConfiguration.getWindowingMode(); if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) { return insetsState.calculateInsets(bounds, null /* ignoringVisibilityState*/, isScreenRound, alwaysConsumeSystemBars, displayCutout.get(), - SOFT_INPUT_ADJUST_NOTHING, attrs.flags, - SYSTEM_UI_FLAG_VISIBLE, null /* typeSideMap */); + SOFT_INPUT_ADJUST_NOTHING, attrs.flags, SYSTEM_UI_FLAG_VISIBLE, attrs.type, + windowingMode, null /* typeSideMap */); } else { return new WindowInsets.Builder() .setAlwaysConsumeSystemBars(alwaysConsumeSystemBars) diff --git a/core/java/android/window/DisplayAreaOrganizer.java b/core/java/android/window/DisplayAreaOrganizer.java index f035d36a0f71..78fa30358d74 100644 --- a/core/java/android/window/DisplayAreaOrganizer.java +++ b/core/java/android/window/DisplayAreaOrganizer.java @@ -20,7 +20,6 @@ import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.TestApi; import android.os.RemoteException; -import android.util.Singleton; import android.view.SurfaceControl; /** @@ -135,22 +134,12 @@ public class DisplayAreaOrganizer extends WindowOrganizer { } }; - private static IDisplayAreaOrganizerController getController() { - return IDisplayAreaOrganizerControllerSingleton.get(); + private IDisplayAreaOrganizerController getController() { + try { + return getWindowOrganizerController().getDisplayAreaOrganizerController(); + } catch (RemoteException e) { + return null; + } } - private static final Singleton<IDisplayAreaOrganizerController> - IDisplayAreaOrganizerControllerSingleton = - new Singleton<IDisplayAreaOrganizerController>() { - @Override - protected IDisplayAreaOrganizerController create() { - try { - return getWindowOrganizerController() - .getDisplayAreaOrganizerController(); - } catch (RemoteException e) { - return null; - } - } - }; - } diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java index 38fb023a0822..d8f2bb248fd1 100644 --- a/core/java/android/window/TaskOrganizer.java +++ b/core/java/android/window/TaskOrganizer.java @@ -23,9 +23,10 @@ import android.annotation.RequiresPermission; import android.annotation.TestApi; import android.app.ActivityManager; import android.os.RemoteException; -import android.util.Singleton; import android.view.SurfaceControl; +import com.android.internal.annotations.VisibleForTesting; + import java.util.List; /** @@ -35,13 +36,25 @@ import java.util.List; @TestApi public class TaskOrganizer extends WindowOrganizer { + private ITaskOrganizerController mTaskOrganizerController; + + public TaskOrganizer() { + mTaskOrganizerController = getController(); + } + + /** @hide */ + @VisibleForTesting + public TaskOrganizer(ITaskOrganizerController taskOrganizerController) { + mTaskOrganizerController = taskOrganizerController; + } + /** * Register a TaskOrganizer to manage tasks as they enter a supported windowing mode. */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void registerOrganizer() { try { - getController().registerTaskOrganizer(mInterface); + mTaskOrganizerController.registerTaskOrganizer(mInterface); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -51,7 +64,7 @@ public class TaskOrganizer extends WindowOrganizer { @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void unregisterOrganizer() { try { - getController().unregisterTaskOrganizer(mInterface); + mTaskOrganizerController.unregisterTaskOrganizer(mInterface); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -78,9 +91,9 @@ public class TaskOrganizer extends WindowOrganizer { /** Creates a persistent root task in WM for a particular windowing-mode. */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) @Nullable - public static ActivityManager.RunningTaskInfo createRootTask(int displayId, int windowingMode) { + public ActivityManager.RunningTaskInfo createRootTask(int displayId, int windowingMode) { try { - return getController().createRootTask(displayId, windowingMode); + return mTaskOrganizerController.createRootTask(displayId, windowingMode); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -88,9 +101,9 @@ public class TaskOrganizer extends WindowOrganizer { /** Deletes a persistent root task in WM */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) - public static boolean deleteRootTask(@NonNull WindowContainerToken task) { + public boolean deleteRootTask(@NonNull WindowContainerToken task) { try { - return getController().deleteRootTask(task); + return mTaskOrganizerController.deleteRootTask(task); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -99,10 +112,10 @@ public class TaskOrganizer extends WindowOrganizer { /** Gets direct child tasks (ordered from top-to-bottom) */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) @Nullable - public static List<ActivityManager.RunningTaskInfo> getChildTasks( + public List<ActivityManager.RunningTaskInfo> getChildTasks( @NonNull WindowContainerToken parent, @NonNull int[] activityTypes) { try { - return getController().getChildTasks(parent, activityTypes); + return mTaskOrganizerController.getChildTasks(parent, activityTypes); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -111,10 +124,10 @@ public class TaskOrganizer extends WindowOrganizer { /** Gets all root tasks on a display (ordered from top-to-bottom) */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) @Nullable - public static List<ActivityManager.RunningTaskInfo> getRootTasks( + public List<ActivityManager.RunningTaskInfo> getRootTasks( int displayId, @NonNull int[] activityTypes) { try { - return getController().getRootTasks(displayId, activityTypes); + return mTaskOrganizerController.getRootTasks(displayId, activityTypes); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -123,9 +136,9 @@ public class TaskOrganizer extends WindowOrganizer { /** Get the root task which contains the current ime target */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) @Nullable - public static WindowContainerToken getImeTarget(int display) { + public WindowContainerToken getImeTarget(int display) { try { - return getController().getImeTarget(display); + return mTaskOrganizerController.getImeTarget(display); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -136,9 +149,9 @@ public class TaskOrganizer extends WindowOrganizer { * root and thus new tasks just end up directly on the display. */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) - public static void setLaunchRoot(int displayId, @NonNull WindowContainerToken root) { + public void setLaunchRoot(int displayId, @NonNull WindowContainerToken root) { try { - getController().setLaunchRoot(displayId, root); + mTaskOrganizerController.setLaunchRoot(displayId, root); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -152,7 +165,7 @@ public class TaskOrganizer extends WindowOrganizer { public void setInterceptBackPressedOnTaskRoot(@NonNull WindowContainerToken task, boolean interceptBackPressed) { try { - getController().setInterceptBackPressedOnTaskRoot(task, interceptBackPressed); + mTaskOrganizerController.setInterceptBackPressedOnTaskRoot(task, interceptBackPressed); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -181,19 +194,11 @@ public class TaskOrganizer extends WindowOrganizer { } }; - private static ITaskOrganizerController getController() { - return ITaskOrganizerControllerSingleton.get(); + private ITaskOrganizerController getController() { + try { + return getWindowOrganizerController().getTaskOrganizerController(); + } catch (RemoteException e) { + return null; + } } - - private static final Singleton<ITaskOrganizerController> ITaskOrganizerControllerSingleton = - new Singleton<ITaskOrganizerController>() { - @Override - protected ITaskOrganizerController create() { - try { - return getWindowOrganizerController().getTaskOrganizerController(); - } catch (RemoteException e) { - return null; - } - } - }; } diff --git a/core/java/android/window/TaskOrganizerTaskEmbedder.java b/core/java/android/window/TaskOrganizerTaskEmbedder.java index eb9dfed7f644..1e293df38cf8 100644 --- a/core/java/android/window/TaskOrganizerTaskEmbedder.java +++ b/core/java/android/window/TaskOrganizerTaskEmbedder.java @@ -109,7 +109,7 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder { } WindowContainerTransaction wct = new WindowContainerTransaction(); wct.setHidden(mTaskToken, false /* hidden */); - WindowOrganizer.applyTransaction(wct); + mTaskOrganizer.applyTransaction(wct); // TODO(b/151449487): Only call callback once we enable synchronization if (mListener != null) { mListener.onTaskVisibilityChanged(getTaskId(), true); @@ -133,7 +133,7 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder { } WindowContainerTransaction wct = new WindowContainerTransaction(); wct.setHidden(mTaskToken, true /* hidden */); - WindowOrganizer.applyTransaction(wct); + mTaskOrganizer.applyTransaction(wct); // TODO(b/151449487): Only call callback once we enable synchronization if (mListener != null) { mListener.onTaskVisibilityChanged(getTaskId(), false); @@ -165,7 +165,7 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder { WindowContainerTransaction wct = new WindowContainerTransaction(); wct.setBounds(mTaskToken, screenBounds); // TODO(b/151449487): Enable synchronization - WindowOrganizer.applyTransaction(wct); + mTaskOrganizer.applyTransaction(wct); } /** diff --git a/core/java/android/window/WindowOrganizer.java b/core/java/android/window/WindowOrganizer.java index ff40ddac134e..97a97d9984f9 100644 --- a/core/java/android/window/WindowOrganizer.java +++ b/core/java/android/window/WindowOrganizer.java @@ -38,7 +38,7 @@ public class WindowOrganizer { * @param t The transaction to apply. */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) - public static void applyTransaction(@NonNull WindowContainerTransaction t) { + public void applyTransaction(@NonNull WindowContainerTransaction t) { try { getWindowOrganizerController().applyTransaction(t); } catch (RemoteException e) { @@ -74,7 +74,7 @@ public class WindowOrganizer { */ @Nullable @RequiresPermission(android.Manifest.permission.READ_FRAME_BUFFER) - public static SurfaceControl takeScreenshot(@NonNull WindowContainerToken token) { + public SurfaceControl takeScreenshot(@NonNull WindowContainerToken token) { try { SurfaceControl surfaceControl = new SurfaceControl(); if (getWindowOrganizerController().takeScreenshot(token, surfaceControl)) { @@ -88,7 +88,7 @@ public class WindowOrganizer { } @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) - static IWindowOrganizerController getWindowOrganizerController() { + IWindowOrganizerController getWindowOrganizerController() { return IWindowOrganizerControllerSingleton.get(); } diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index b12c5e9ba5b0..a6c3dd1071c9 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -24,6 +24,7 @@ import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.N; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR; +import static android.view.InsetsState.clearCompatInsets; import static android.view.View.MeasureSpec.AT_MOST; import static android.view.View.MeasureSpec.EXACTLY; import static android.view.View.MeasureSpec.getMode; @@ -1097,10 +1098,12 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind final Insets systemBarInsets = insets.getInsets(WindowInsets.Type.systemBars()); final Insets stableBarInsets = insets.getInsetsIgnoringVisibility( WindowInsets.Type.systemBars()); - mLastTopInset = systemBarInsets.top; - mLastBottomInset = systemBarInsets.bottom; - mLastRightInset = systemBarInsets.right; - mLastLeftInset = systemBarInsets.left; + final boolean clearCompatInsets = clearCompatInsets(attrs.type, attrs.flags, + getResources().getConfiguration().windowConfiguration.getWindowingMode()); + mLastTopInset = clearCompatInsets ? 0 : systemBarInsets.top; + mLastBottomInset = clearCompatInsets ? 0 : systemBarInsets.bottom; + mLastRightInset = clearCompatInsets ? 0 : systemBarInsets.right; + mLastLeftInset = clearCompatInsets ? 0 : systemBarInsets.left; // Don't animate if the presence of stable insets has changed, because that // indicates that the window was either just added and received them for the diff --git a/core/java/com/android/internal/policy/TaskResizingAlgorithm.java b/core/java/com/android/internal/policy/TaskResizingAlgorithm.java index 1ec020696cf3..64e0b91ae40a 100644 --- a/core/java/com/android/internal/policy/TaskResizingAlgorithm.java +++ b/core/java/com/android/internal/policy/TaskResizingAlgorithm.java @@ -51,8 +51,6 @@ public class TaskResizingAlgorithm { public static final int CTRL_BOTTOM = 0x8; // The minimal aspect ratio which needs to be met to count as landscape (or 1/.. for portrait). - // Note: We do not use the 1.33 from the CDD here since the user is allowed to use what ever - // aspect he desires. @VisibleForTesting public static final float MIN_ASPECT = 1.2f; diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 5c4c5099bf4c..3f39478ffd43 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -2407,79 +2407,6 @@ static jint android_media_AudioSystem_getDevicesForRoleAndStrategy(JNIEnv *env, return AUDIO_JAVA_SUCCESS; } -static jint android_media_AudioSystem_setDevicesRoleForCapturePreset( - JNIEnv *env, jobject thiz, jint capturePreset, jint role, jintArray jDeviceTypes, - jobjectArray jDeviceAddresses) { - AudioDeviceTypeAddrVector nDevices; - jint results = getVectorOfAudioDeviceTypeAddr(env, jDeviceTypes, jDeviceAddresses, nDevices); - if (results != NO_ERROR) { - return results; - } - int status = check_AudioSystem_Command( - AudioSystem::setDevicesRoleForCapturePreset((audio_source_t)capturePreset, - (device_role_t)role, nDevices)); - return (jint)status; -} - -static jint android_media_AudioSystem_addDevicesRoleForCapturePreset( - JNIEnv *env, jobject thiz, jint capturePreset, jint role, jintArray jDeviceTypes, - jobjectArray jDeviceAddresses) { - AudioDeviceTypeAddrVector nDevices; - jint results = getVectorOfAudioDeviceTypeAddr(env, jDeviceTypes, jDeviceAddresses, nDevices); - if (results != NO_ERROR) { - return results; - } - int status = check_AudioSystem_Command( - AudioSystem::addDevicesRoleForCapturePreset((audio_source_t)capturePreset, - (device_role_t)role, nDevices)); - return (jint)status; -} - -static jint android_media_AudioSystem_removeDevicesRoleForCapturePreset( - JNIEnv *env, jobject thiz, jint capturePreset, jint role, jintArray jDeviceTypes, - jobjectArray jDeviceAddresses) { - AudioDeviceTypeAddrVector nDevices; - jint results = getVectorOfAudioDeviceTypeAddr(env, jDeviceTypes, jDeviceAddresses, nDevices); - if (results != NO_ERROR) { - return results; - } - int status = check_AudioSystem_Command( - AudioSystem::removeDevicesRoleForCapturePreset((audio_source_t)capturePreset, - (device_role_t)role, nDevices)); - return (jint)status; -} - -static jint android_media_AudioSystem_clearDevicesRoleForCapturePreset(JNIEnv *env, jobject thiz, - jint capturePreset, - jint role) { - return (jint)check_AudioSystem_Command( - AudioSystem::clearDevicesRoleForCapturePreset((audio_source_t)capturePreset, - (device_role_t)role)); -} - -static jint android_media_AudioSystem_getDevicesForRoleAndCapturePreset(JNIEnv *env, jobject thiz, - jint capturePreset, - jint role, - jobject jDevices) { - AudioDeviceTypeAddrVector nDevices; - status_t status = check_AudioSystem_Command( - AudioSystem::getDevicesForRoleAndCapturePreset((audio_source_t)capturePreset, - (device_role_t)role, nDevices)); - if (status != NO_ERROR) { - return (jint)status; - } - for (const auto &device : nDevices) { - jobject jAudioDeviceAttributes = NULL; - jint jStatus = createAudioDeviceAttributesFromNative(env, &jAudioDeviceAttributes, &device); - if (jStatus != AUDIO_JAVA_SUCCESS) { - return jStatus; - } - env->CallBooleanMethod(jDevices, gListMethods.add, jAudioDeviceAttributes); - env->DeleteLocalRef(jAudioDeviceAttributes); - } - return AUDIO_JAVA_SUCCESS; -} - static jint android_media_AudioSystem_getDevicesForAttributes(JNIEnv *env, jobject thiz, jobject jaa, jobjectArray jDeviceArray) @@ -2631,16 +2558,6 @@ static const JNINativeMethod gMethods[] = (void *)android_media_AudioSystem_removeDevicesRoleForStrategy}, {"getDevicesForRoleAndStrategy", "(IILjava/util/List;)I", (void *)android_media_AudioSystem_getDevicesForRoleAndStrategy}, - {"setDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I", - (void *)android_media_AudioSystem_setDevicesRoleForCapturePreset}, - {"addDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I", - (void *)android_media_AudioSystem_addDevicesRoleForCapturePreset}, - {"removeDevicesRoleForCapturePreset", "(II[I[Ljava/lang/String;)I", - (void *)android_media_AudioSystem_removeDevicesRoleForCapturePreset}, - {"clearDevicesRoleForCapturePreset", "(II)I", - (void *)android_media_AudioSystem_clearDevicesRoleForCapturePreset}, - {"getDevicesForRoleAndCapturePreset", "(IILjava/util/List;)I", - (void *)android_media_AudioSystem_getDevicesForRoleAndCapturePreset}, {"getDevicesForAttributes", "(Landroid/media/AudioAttributes;[Landroid/media/AudioDeviceAttributes;)I", (void *)android_media_AudioSystem_getDevicesForAttributes}, diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 0e176b53f236..feef587dd685 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -1283,7 +1283,7 @@ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"nepoznata vrsta mreže"</string> <string name="accept" msgid="5447154347815825107">"Prihvati"</string> <string name="decline" msgid="6490507610282145874">"Odbijte"</string> - <string name="select_character" msgid="3352797107930786979">"Umetni karakter"</string> + <string name="select_character" msgid="3352797107930786979">"Umetni znak"</string> <string name="sms_control_title" msgid="4748684259903148341">"Slanje SMS poruka"</string> <string name="sms_control_message" msgid="6574313876316388239">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> šalje veliki broj SMS poruka. Da li želite dozvoliti ovoj aplikaciji da nastavi slanje poruka?"</string> <string name="sms_control_yes" msgid="4858845109269524622">"Dozvoli"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 0004ff1a3f13..9062435ec9ce 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -1900,8 +1900,8 @@ <string name="profile_encrypted_message" msgid="1128512616293157802">"A feloldáshoz koppintson rá"</string> <string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"Csatlakoztatva a(z) <xliff:g id="PRODUCT_NAME">%1$s</xliff:g> eszközhöz"</string> <string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"Koppintson ide a fájlok megtekintéséhez"</string> - <string name="pin_target" msgid="8036028973110156895">"Rögzítés"</string> - <string name="pin_specific_target" msgid="7824671240625957415">"<xliff:g id="LABEL">%1$s</xliff:g> rögzítése"</string> + <string name="pin_target" msgid="8036028973110156895">"Kitűzés"</string> + <string name="pin_specific_target" msgid="7824671240625957415">"<xliff:g id="LABEL">%1$s</xliff:g> kitűzése"</string> <string name="unpin_target" msgid="3963318576590204447">"Feloldás"</string> <string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> rögzítésének feloldása"</string> <string name="app_info" msgid="6113278084877079851">"Alkalmazásinformáció"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 264a8fcb343d..4f66b6e8a947 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -1979,7 +1979,7 @@ <string name="shortcut_restore_signature_mismatch" msgid="579345304221605479">"Չհաջողվեց վերականգնել դյուրանցումը, քանի որ հավելվածների ստորագրությունները տարբեր են"</string> <string name="shortcut_restore_unknown_issue" msgid="2478146134395982154">"Չհաջողվեց վերականգնել դյուրանցումը"</string> <string name="shortcut_disabled_reason_unknown" msgid="753074793553599166">"Դյուրանցումն անջատված է"</string> - <string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ՀԵՌԱՑՆԵԼ"</string> + <string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ԱՊԱՏԵՂԱԴՐԵԼ"</string> <string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ԲԱՑԵԼ"</string> <string name="harmful_app_warning_title" msgid="8794823880881113856">"Հայտնաբերվել է վնասաբեր հավելված"</string> <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> հավելվածն ուզում է ցուցադրել հատվածներ <xliff:g id="APP_2">%2$s</xliff:g> հավելվածից"</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index a65f80c9332f..2c041dced482 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -1120,7 +1120,7 @@ <string name="yes" msgid="9069828999585032361">"ОК"</string> <string name="no" msgid="5122037903299899715">"Цуцлах"</string> <string name="dialog_alert_title" msgid="651856561974090712">"Анхаар"</string> - <string name="loading" msgid="3138021523725055037">"Ачааллаж байна..."</string> + <string name="loading" msgid="3138021523725055037">"Ачаалж байна..."</string> <string name="capital_on" msgid="2770685323900821829">"Идэвхтэй"</string> <string name="capital_off" msgid="7443704171014626777">"Идэвхгүй"</string> <string name="checked" msgid="9179896827054513119">"тэмдэглэсэн"</string> diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java index eb695258142a..a5b7c6156109 100644 --- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java +++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java @@ -16,9 +16,11 @@ package android.view; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.ImeInsetsSourceConsumer.areEditorsSimilar; import static android.view.InsetsState.ITYPE_IME; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; @@ -86,6 +88,7 @@ public class ImeInsetsSourceConsumerTest { false, new DisplayCutout( Insets.of(10, 10, 10, 10), rect, rect, rect, rect), + TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, SOFT_INPUT_ADJUST_RESIZE, 0, 0); mImeConsumer = (ImeInsetsSourceConsumer) mController.getSourceConsumer(ITYPE_IME); }); diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java index de128ad6d78e..88e1f5781e0e 100644 --- a/core/tests/coretests/src/android/view/InsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java @@ -16,6 +16,7 @@ package android.view; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.InsetsController.ANIMATION_TYPE_HIDE; import static android.view.InsetsController.ANIMATION_TYPE_NONE; import static android.view.InsetsController.ANIMATION_TYPE_SHOW; @@ -30,6 +31,7 @@ import static android.view.WindowInsets.Type.ime; import static android.view.WindowInsets.Type.navigationBars; import static android.view.WindowInsets.Type.statusBars; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -169,6 +171,7 @@ public class InsetsControllerTest { false, new DisplayCutout( Insets.of(10, 10, 10, 10), rect, rect, rect, rect), + TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, SOFT_INPUT_ADJUST_RESIZE, 0, 0); mController.onFrameChanged(new Rect(0, 0, 100, 100)); }); diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java index c7d835ca7c7e..4306e3e0fe7b 100644 --- a/core/tests/coretests/src/android/view/InsetsStateTest.java +++ b/core/tests/coretests/src/android/view/InsetsStateTest.java @@ -16,6 +16,8 @@ package android.view; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.InsetsState.ISIDE_BOTTOM; import static android.view.InsetsState.ISIDE_TOP; import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES; @@ -30,9 +32,13 @@ import static android.view.WindowInsets.Type.ime; import static android.view.WindowInsets.Type.navigationBars; import static android.view.WindowInsets.Type.statusBars; import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; +import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; +import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -78,7 +84,8 @@ public class InsetsStateTest { mState.getSource(ITYPE_IME).setVisible(true); SparseIntArray typeSideMap = new SparseIntArray(); WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, - false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, 0, typeSideMap); + false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, 0, + TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, typeSideMap); assertEquals(Insets.of(0, 100, 0, 100), insets.getSystemWindowInsets()); assertEquals(Insets.of(0, 100, 0, 100), insets.getInsets(Type.all())); assertEquals(ISIDE_TOP, typeSideMap.get(ITYPE_STATUS_BAR)); @@ -97,7 +104,8 @@ public class InsetsStateTest { mState.getSource(ITYPE_IME).setFrame(new Rect(0, 100, 100, 300)); mState.getSource(ITYPE_IME).setVisible(true); WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, - false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, 0, null); + false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, 0, + TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null); assertEquals(100, insets.getStableInsetBottom()); assertEquals(Insets.of(0, 0, 0, 100), insets.getInsetsIgnoringVisibility(Type.systemBars())); assertEquals(Insets.of(0, 0, 0, 200), insets.getSystemWindowInsets()); @@ -116,7 +124,8 @@ public class InsetsStateTest { mState.getSource(ITYPE_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300)); mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(true); WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, - false, DisplayCutout.NO_CUTOUT, 0, 0, 0, null); + false, DisplayCutout.NO_CUTOUT, 0, 0, 0, TYPE_APPLICATION, + WINDOWING_MODE_UNDEFINED, null); assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets()); assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.statusBars())); assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.navigationBars())); @@ -132,7 +141,8 @@ public class InsetsStateTest { mState.getSource(ITYPE_IME).setFrame(new Rect(0, 200, 100, 300)); mState.getSource(ITYPE_IME).setVisible(true); WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, - false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, 0, 0, null); + false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, 0, 0, + TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null); assertEquals(0, insets.getSystemWindowInsetBottom()); assertEquals(100, insets.getInsets(ime()).bottom); assertTrue(insets.isVisible(ime())); @@ -149,11 +159,11 @@ public class InsetsStateTest { mState.getSource(ITYPE_IME).setVisible(true); WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, 0, - SYSTEM_UI_FLAG_LAYOUT_STABLE, null); + SYSTEM_UI_FLAG_LAYOUT_STABLE, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null); assertEquals(100, insets.getSystemWindowInsetTop()); insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, 0, - 0 /* legacySystemUiFlags */, null); + 0 /* legacySystemUiFlags */, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null); assertEquals(0, insets.getSystemWindowInsetTop()); } } @@ -166,15 +176,37 @@ public class InsetsStateTest { mState.getSource(ITYPE_STATUS_BAR).setVisible(false); WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, FLAG_FULLSCREEN, - SYSTEM_UI_FLAG_LAYOUT_STABLE, null); + SYSTEM_UI_FLAG_LAYOUT_STABLE, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null); assertEquals(0, insets.getSystemWindowInsetTop()); insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, 0, - 0 /* legacySystemUiFlags */, null); + 0 /* legacySystemUiFlags */, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null); assertEquals(0, insets.getSystemWindowInsetTop()); } } + @Test + public void testCalculateInsets_flagLayoutNoLimits() { + mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 100)); + mState.getSource(ITYPE_STATUS_BAR).setVisible(true); + WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, + false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS, + 0 /* legacySystemUiFlags */, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, null); + assertEquals(0, insets.getSystemWindowInsetTop()); + insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, + false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS, + 0 /* legacySystemUiFlags */, TYPE_SYSTEM_ERROR, WINDOWING_MODE_UNDEFINED, null); + assertEquals(100, insets.getSystemWindowInsetTop()); + insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, + false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS, + 0 /* legacySystemUiFlags */, TYPE_WALLPAPER, WINDOWING_MODE_UNDEFINED, null); + assertEquals(100, insets.getSystemWindowInsetTop()); + insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, + false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, FLAG_LAYOUT_NO_LIMITS, + 0 /* legacySystemUiFlags */, TYPE_APPLICATION, WINDOWING_MODE_FREEFORM, null); + assertEquals(100, insets.getSystemWindowInsetTop()); + } + @Test public void testCalculateInsets_captionStatusBarOverlap() throws Exception { @@ -213,7 +245,8 @@ public class InsetsStateTest { mState.getSource(ITYPE_EXTRA_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300)); mState.getSource(ITYPE_EXTRA_NAVIGATION_BAR).setVisible(true); WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, - false, DisplayCutout.NO_CUTOUT, 0, 0, 0, null); + false, DisplayCutout.NO_CUTOUT, 0, 0, 0, TYPE_APPLICATION, + WINDOWING_MODE_UNDEFINED, null); assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets()); assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.statusBars())); assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.navigationBars())); @@ -229,7 +262,8 @@ public class InsetsStateTest { mState.getSource(ITYPE_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300)); mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(true); WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, - false, DisplayCutout.NO_CUTOUT, 0, 0, 0, null); + false, DisplayCutout.NO_CUTOUT, 0, 0, 0, TYPE_APPLICATION, + WINDOWING_MODE_UNDEFINED, null); assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets()); assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.statusBars())); assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.navigationBars())); @@ -244,7 +278,8 @@ public class InsetsStateTest { mState.getSource(ITYPE_IME).setVisible(true); mState.removeSource(ITYPE_IME); WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false, - DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, 0, null); + DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, 0, TYPE_APPLICATION, + WINDOWING_MODE_UNDEFINED, null); assertEquals(0, insets.getSystemWindowInsetBottom()); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java index ea9576a511e9..f9ba695c8503 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -17,23 +17,23 @@ package com.android.wm.shell; import android.app.ActivityManager.RunningTaskInfo; -import android.app.WindowConfiguration; -import android.content.Context; import android.util.Log; import android.util.Pair; import android.util.SparseArray; import android.view.SurfaceControl; +import android.window.ITaskOrganizerController; import android.window.TaskOrganizer; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.protolog.ShellProtoLogGroup; -import com.android.wm.shell.protolog.ShellProtoLogImpl; import java.util.ArrayList; import java.util.Arrays; /** * Unified task organizer for all components in the shell. + * TODO(b/167582004): may consider consolidating this class and TaskOrganizer */ public class ShellTaskOrganizer extends TaskOrganizer { @@ -56,6 +56,15 @@ public class ShellTaskOrganizer extends TaskOrganizer { // require us to report to both old and new listeners) private final SparseArray<Pair<RunningTaskInfo, SurfaceControl>> mTasks = new SparseArray<>(); + public ShellTaskOrganizer() { + super(); + } + + @VisibleForTesting + ShellTaskOrganizer(ITaskOrganizerController taskOrganizerController) { + super(taskOrganizerController); + } + /** * Adds a listener for tasks in a specific windowing mode. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerImeController.java index 92cee8a1a874..ff617ed466d1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerImeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerImeController.java @@ -30,7 +30,6 @@ import android.view.SurfaceControl; import android.window.TaskOrganizer; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; -import android.window.WindowOrganizer; import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.TransactionPool; @@ -44,6 +43,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor private final SplitScreenTaskOrganizer mSplits; private final TransactionPool mTransactionPool; private final Handler mHandler; + private final TaskOrganizer mTaskOrganizer; /** * These are the y positions of the top of the IME surface when it is hidden and when it is @@ -92,10 +92,12 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor private boolean mPausedTargetAdjusted = false; private boolean mAdjustedWhileHidden = false; - DividerImeController(SplitScreenTaskOrganizer splits, TransactionPool pool, Handler handler) { + DividerImeController(SplitScreenTaskOrganizer splits, TransactionPool pool, Handler handler, + TaskOrganizer taskOrganizer) { mSplits = splits; mTransactionPool = pool; mHandler = handler; + mTaskOrganizer = taskOrganizer; } private DividerView getView() { @@ -111,7 +113,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor } private boolean getSecondaryHasFocus(int displayId) { - WindowContainerToken imeSplit = TaskOrganizer.getImeTarget(displayId); + WindowContainerToken imeSplit = mTaskOrganizer.getImeTarget(displayId); return imeSplit != null && (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder()); } @@ -236,7 +238,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor } if (!mSplits.mSplitScreenController.getWmProxy().queueSyncTransactionIfWaiting(wct)) { - WindowOrganizer.applyTransaction(wct); + mTaskOrganizer.applyTransaction(wct); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java index 79bfda92bd92..00146e9447bd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java @@ -619,7 +619,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, mEntranceAnimationRunning = false; mExitAnimationRunning = false; if (!dismissed && !wasMinimizeInteraction) { - WindowManagerProxy.applyResizeSplits(snapTarget.position, mSplitLayout); + mWindowManagerProxy.applyResizeSplits(snapTarget.position, mSplitLayout); } if (mCallback != null) { mCallback.onDraggingEnd(); @@ -889,7 +889,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, t.hide(sc).apply(); mTiles.releaseTransaction(t); int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position; - WindowManagerProxy.applyResizeSplits(midPos, mSplitLayout); + mWindowManagerProxy.applyResizeSplits(midPos, mSplitLayout); } void setMinimizedDockStack(boolean minimized, long animDuration, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index d5326d4845a3..eed5092ea96b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -29,9 +29,9 @@ import android.provider.Settings; import android.util.Slog; import android.view.LayoutInflater; import android.view.View; +import android.window.TaskOrganizer; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; -import android.window.WindowOrganizer; import com.android.internal.policy.DividerSnapAlgorithm; import com.android.wm.shell.R; @@ -71,6 +71,7 @@ public class SplitScreenController implements SplitScreen, private final SystemWindows mSystemWindows; final TransactionPool mTransactionPool; private final WindowManagerProxy mWindowManagerProxy; + private final TaskOrganizer mTaskOrganizer; private final ArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners = new ArrayList<>(); @@ -106,9 +107,12 @@ public class SplitScreenController implements SplitScreen, mHandler = handler; mForcedResizableController = new ForcedResizableInfoActivityController(context, this); mTransactionPool = transactionPool; - mWindowManagerProxy = new WindowManagerProxy(mTransactionPool, mHandler); + mWindowManagerProxy = new WindowManagerProxy(mTransactionPool, mHandler, + shellTaskOrganizer); + mTaskOrganizer = shellTaskOrganizer; mSplits = new SplitScreenTaskOrganizer(this, shellTaskOrganizer); - mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mHandler); + mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mHandler, + shellTaskOrganizer); mRotationController = (display, fromRotation, toRotation, wct) -> { if (!mSplits.isSplitScreenSupported() || mWindowManagerProxy == null) { @@ -132,7 +136,7 @@ public class SplitScreenController implements SplitScreen, sdl.resizeSplits(target.position, t); if (isSplitActive() && mHomeStackResizable) { - WindowManagerProxy + mWindowManagerProxy .applyHomeTasksMinimized(sdl, mSplits.mSecondary.token, t); } if (mWindowManagerProxy.queueSyncTransactionIfWaiting(t)) { @@ -189,7 +193,7 @@ public class SplitScreenController implements SplitScreen, final WindowContainerTransaction tct = new WindowContainerTransaction(); int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position; mSplitLayout.resizeSplits(midPos, tct); - WindowOrganizer.applyTransaction(tct); + mTaskOrganizer.applyTransaction(tct); } catch (Exception e) { Slog.e(TAG, "Failed to register docked stack listener", e); removeDivider(); @@ -208,7 +212,7 @@ public class SplitScreenController implements SplitScreen, int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position; final WindowContainerTransaction tct = new WindowContainerTransaction(); mSplitLayout.resizeSplits(midPos, tct); - WindowOrganizer.applyTransaction(tct); + mTaskOrganizer.applyTransaction(tct); } else if (mSplitLayout.mDisplayLayout.rotation() == mRotateSplitLayout.mDisplayLayout.rotation()) { mSplitLayout.mPrimary = new Rect(mRotateSplitLayout.mPrimary); @@ -372,7 +376,7 @@ public class SplitScreenController implements SplitScreen, // If we are only setting focusability, a sync transaction isn't necessary (in fact it // can interrupt other animations), so see if it can be submitted on pending instead. if (!mWindowManagerProxy.queueSyncTransactionIfWaiting(wct)) { - WindowOrganizer.applyTransaction(wct); + mTaskOrganizer.applyTransaction(wct); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskOrganizer.java index 6d28c5e17d42..30bc43b0292f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskOrganizer.java @@ -31,7 +31,6 @@ import android.util.Log; import android.view.Display; import android.view.SurfaceControl; import android.view.SurfaceSession; -import android.window.TaskOrganizer; import com.android.wm.shell.ShellTaskOrganizer; @@ -64,9 +63,9 @@ class SplitScreenTaskOrganizer implements ShellTaskOrganizer.TaskListener { void init() throws RemoteException { synchronized (this) { try { - mPrimary = TaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY, + mPrimary = mTaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY, WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); - mSecondary = TaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY, + mSecondary = mTaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY, WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); } catch (Exception e) { // teardown to prevent callbacks diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java index cd96676ad1fe..015707ecc6c8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java @@ -83,8 +83,12 @@ class WindowManagerProxy { } }; - WindowManagerProxy(TransactionPool transactionPool, Handler handler) { + private final TaskOrganizer mTaskOrganizer; + + WindowManagerProxy(TransactionPool transactionPool, Handler handler, + TaskOrganizer taskOrganizer) { mSyncTransactionQueue = new SyncTransactionQueue(transactionPool, handler); + mTaskOrganizer = taskOrganizer; } void dismissOrMaximizeDocked(final SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout, @@ -113,18 +117,18 @@ class WindowManagerProxy { mExecutor.execute(mSetTouchableRegionRunnable); } - static void applyResizeSplits(int position, SplitDisplayLayout splitLayout) { + void applyResizeSplits(int position, SplitDisplayLayout splitLayout) { WindowContainerTransaction t = new WindowContainerTransaction(); splitLayout.resizeSplits(position, t); - WindowOrganizer.applyTransaction(t); + new WindowOrganizer().applyTransaction(t); } - private static boolean getHomeAndRecentsTasks(List<ActivityManager.RunningTaskInfo> out, + private boolean getHomeAndRecentsTasks(List<ActivityManager.RunningTaskInfo> out, WindowContainerToken parent) { boolean resizable = false; List<ActivityManager.RunningTaskInfo> rootTasks = parent == null - ? TaskOrganizer.getRootTasks(Display.DEFAULT_DISPLAY, HOME_AND_RECENTS) - : TaskOrganizer.getChildTasks(parent, HOME_AND_RECENTS); + ? mTaskOrganizer.getRootTasks(Display.DEFAULT_DISPLAY, HOME_AND_RECENTS) + : mTaskOrganizer.getChildTasks(parent, HOME_AND_RECENTS); for (int i = 0, n = rootTasks.size(); i < n; ++i) { final ActivityManager.RunningTaskInfo ti = rootTasks.get(i); out.add(ti); @@ -140,7 +144,7 @@ class WindowManagerProxy { * split is minimized. This actually "sticks out" of the secondary split area, but when in * minimized mode, the secondary split gets a 'negative' crop to expose it. */ - static boolean applyHomeTasksMinimized(SplitDisplayLayout layout, WindowContainerToken parent, + boolean applyHomeTasksMinimized(SplitDisplayLayout layout, WindowContainerToken parent, @NonNull WindowContainerTransaction wct) { // Resize the home/recents stacks to the larger minimized-state size final Rect homeBounds; @@ -192,9 +196,9 @@ class WindowManagerProxy { // Set launchtile first so that any stack created after // getAllStackInfos and before reparent (even if unlikely) are placed // correctly. - TaskOrganizer.setLaunchRoot(DEFAULT_DISPLAY, tiles.mSecondary.token); + mTaskOrganizer.setLaunchRoot(DEFAULT_DISPLAY, tiles.mSecondary.token); List<ActivityManager.RunningTaskInfo> rootTasks = - TaskOrganizer.getRootTasks(DEFAULT_DISPLAY, null /* activityTypes */); + mTaskOrganizer.getRootTasks(DEFAULT_DISPLAY, null /* activityTypes */); WindowContainerTransaction wct = new WindowContainerTransaction(); if (rootTasks.isEmpty()) { return false; @@ -230,7 +234,7 @@ class WindowManagerProxy { return isHomeResizable; } - static boolean isHomeOrRecentTask(ActivityManager.RunningTaskInfo ti) { + boolean isHomeOrRecentTask(ActivityManager.RunningTaskInfo ti) { final int atype = ti.configuration.windowConfiguration.getActivityType(); return atype == ACTIVITY_TYPE_HOME || atype == ACTIVITY_TYPE_RECENTS; } @@ -245,18 +249,18 @@ class WindowManagerProxy { boolean dismissOrMaximize) { // Set launch root first so that any task created after getChildContainers and // before reparent (pretty unlikely) are put into fullscreen. - TaskOrganizer.setLaunchRoot(Display.DEFAULT_DISPLAY, null); + mTaskOrganizer.setLaunchRoot(Display.DEFAULT_DISPLAY, null); // TODO(task-org): Once task-org is more complete, consider using Appeared/Vanished // plus specific APIs to clean this up. List<ActivityManager.RunningTaskInfo> primaryChildren = - TaskOrganizer.getChildTasks(tiles.mPrimary.token, null /* activityTypes */); + mTaskOrganizer.getChildTasks(tiles.mPrimary.token, null /* activityTypes */); List<ActivityManager.RunningTaskInfo> secondaryChildren = - TaskOrganizer.getChildTasks(tiles.mSecondary.token, null /* activityTypes */); + mTaskOrganizer.getChildTasks(tiles.mSecondary.token, null /* activityTypes */); // In some cases (eg. non-resizable is launched), system-server will leave split-screen. // as a result, the above will not capture any tasks; yet, we need to clean-up the // home task bounds. List<ActivityManager.RunningTaskInfo> freeHomeAndRecents = - TaskOrganizer.getRootTasks(DEFAULT_DISPLAY, HOME_AND_RECENTS); + mTaskOrganizer.getRootTasks(DEFAULT_DISPLAY, HOME_AND_RECENTS); // Filter out the root split tasks freeHomeAndRecents.removeIf(p -> p.token.equals(tiles.mSecondary.token) || p.token.equals(tiles.mPrimary.token)); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java index 10672c8d87ad..497b6b714281 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java @@ -20,10 +20,14 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; import android.app.ActivityManager.RunningTaskInfo; -import android.content.res.Configuration; +import android.os.RemoteException; import android.view.SurfaceControl; +import android.window.ITaskOrganizer; +import android.window.ITaskOrganizerController; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -31,6 +35,8 @@ import androidx.test.filters.SmallTest; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import java.util.ArrayList; @@ -41,6 +47,9 @@ import java.util.ArrayList; @RunWith(AndroidJUnit4.class) public class ShellTaskOrganizerTests { + @Mock + private ITaskOrganizerController mTaskOrganizerController; + ShellTaskOrganizer mOrganizer; private class TrackingTaskListener implements ShellTaskOrganizer.TaskListener { @@ -71,7 +80,15 @@ public class ShellTaskOrganizerTests { @Before public void setUp() { - mOrganizer = new ShellTaskOrganizer(); + MockitoAnnotations.initMocks(this); + mOrganizer = new ShellTaskOrganizer(mTaskOrganizerController); + } + + @Test + public void registerOrganizer_sendRegisterTaskOrganizer() throws RemoteException { + mOrganizer.registerOrganizer(); + + verify(mTaskOrganizerController).registerTaskOrganizer(any(ITaskOrganizer.class)); } @Test diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index 76ec078ce3c9..4dbce92ed01c 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -84,7 +84,6 @@ VulkanManager::~VulkanManager() { mGraphicsQueue = VK_NULL_HANDLE; mAHBUploadQueue = VK_NULL_HANDLE; - mPresentQueue = VK_NULL_HANDLE; mDevice = VK_NULL_HANDLE; mPhysicalDevice = VK_NULL_HANDLE; mInstance = VK_NULL_HANDLE; @@ -192,10 +191,6 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe } LOG_ALWAYS_FATAL_IF(mGraphicsQueueIndex == queueCount); - // All physical devices and queue families on Android must be capable of - // presentation with any native window. So just use the first one. - mPresentQueueIndex = 0; - { uint32_t extensionCount = 0; err = mEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr, &extensionCount, @@ -289,31 +284,21 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe queueNextPtr = &queuePriorityCreateInfo; } - const VkDeviceQueueCreateInfo queueInfo[2] = { - { - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType - queueNextPtr, // pNext - 0, // VkDeviceQueueCreateFlags - mGraphicsQueueIndex, // queueFamilyIndex - 2, // queueCount - queuePriorities, // pQueuePriorities - }, - { - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType - queueNextPtr, // pNext - 0, // VkDeviceQueueCreateFlags - mPresentQueueIndex, // queueFamilyIndex - 1, // queueCount - queuePriorities, // pQueuePriorities - }}; - uint32_t queueInfoCount = (mPresentQueueIndex != mGraphicsQueueIndex) ? 2 : 1; + const VkDeviceQueueCreateInfo queueInfo = { + VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType + queueNextPtr, // pNext + 0, // VkDeviceQueueCreateFlags + mGraphicsQueueIndex, // queueFamilyIndex + 2, // queueCount + queuePriorities, // pQueuePriorities + }; const VkDeviceCreateInfo deviceInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType &features, // pNext 0, // VkDeviceCreateFlags - queueInfoCount, // queueCreateInfoCount - queueInfo, // pQueueCreateInfos + 1, // queueCreateInfoCount + &queueInfo, // pQueueCreateInfos 0, // layerCount nullptr, // ppEnabledLayerNames (uint32_t)mDeviceExtensions.size(), // extensionCount @@ -361,8 +346,6 @@ void VulkanManager::initialize() { mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 0, &mGraphicsQueue); mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 1, &mAHBUploadQueue); - mGetDeviceQueue(mDevice, mPresentQueueIndex, 0, &mPresentQueue); - if (Properties::enablePartialUpdates && Properties::useBufferAge) { mSwapBehavior = SwapBehavior::BufferAge; } @@ -555,8 +538,8 @@ void VulkanManager::swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect) void VulkanManager::destroySurface(VulkanSurface* surface) { // Make sure all submit commands have finished before starting to destroy objects. - if (VK_NULL_HANDLE != mPresentQueue) { - mQueueWaitIdle(mPresentQueue); + if (VK_NULL_HANDLE != mGraphicsQueue) { + mQueueWaitIdle(mGraphicsQueue); } mDeviceWaitIdle(mDevice); diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h index 75c05b828e5d..7a77466303cd 100644 --- a/libs/hwui/renderthread/VulkanManager.h +++ b/libs/hwui/renderthread/VulkanManager.h @@ -163,8 +163,6 @@ private: uint32_t mGraphicsQueueIndex; VkQueue mGraphicsQueue = VK_NULL_HANDLE; VkQueue mAHBUploadQueue = VK_NULL_HANDLE; - uint32_t mPresentQueueIndex; - VkQueue mPresentQueue = VK_NULL_HANDLE; // Variables saved to populate VkFunctorInitParams. static const uint32_t mAPIVersion = VK_MAKE_VERSION(1, 1, 0); diff --git a/location/java/android/location/timezone/LocationTimeZoneEvent.java b/location/java/android/location/timezone/LocationTimeZoneEvent.java index 540bdfffe16a..55bc507964e6 100644 --- a/location/java/android/location/timezone/LocationTimeZoneEvent.java +++ b/location/java/android/location/timezone/LocationTimeZoneEvent.java @@ -35,7 +35,8 @@ import java.util.Objects; */ public final class LocationTimeZoneEvent implements Parcelable { - @IntDef({ EVENT_TYPE_UNKNOWN, EVENT_TYPE_SUCCESS, EVENT_TYPE_SUCCESS }) + @IntDef({ EVENT_TYPE_UNKNOWN, EVENT_TYPE_PERMANENT_FAILURE, EVENT_TYPE_SUCCESS, + EVENT_TYPE_UNCERTAIN }) @interface EventType {} /** Uninitialized value for {@link #mEventType} - must not be used for real events. */ @@ -43,7 +44,7 @@ public final class LocationTimeZoneEvent implements Parcelable { /** * Indicates there was a permanent failure. This is not generally expected, and probably means a - * required backend service is no longer supported / available. + * required backend service has been turned down, or the client is unreasonably old. */ public static final int EVENT_TYPE_PERMANENT_FAILURE = 1; @@ -54,8 +55,9 @@ public final class LocationTimeZoneEvent implements Parcelable { public static final int EVENT_TYPE_SUCCESS = 2; /** - * Indicates the time zone is not known because there was a (temporary) error, e.g. when - * detecting location, or when resolving the location to a time zone. + * Indicates the time zone is not known because of an expected runtime state or error, e.g. when + * the provider is unable to detect location, or there was a problem when resolving the location + * to a time zone. */ public static final int EVENT_TYPE_UNCERTAIN = 3; diff --git a/media/java/android/media/AudioDeviceAttributes.java b/media/java/android/media/AudioDeviceAttributes.java index 5096bf616a1f..0ab62c14ab9f 100644 --- a/media/java/android/media/AudioDeviceAttributes.java +++ b/media/java/android/media/AudioDeviceAttributes.java @@ -72,11 +72,6 @@ public final class AudioDeviceAttributes implements Parcelable { private final @Role int mRole; /** - * The internal audio device type - */ - private final int mNativeType; - - /** * @hide * Constructor from a valid {@link AudioDeviceInfo} * @param deviceInfo the connected audio device from which to obtain the device-identifying @@ -88,7 +83,6 @@ public final class AudioDeviceAttributes implements Parcelable { mRole = deviceInfo.isSink() ? ROLE_OUTPUT : ROLE_INPUT; mType = deviceInfo.getType(); mAddress = deviceInfo.getAddress(); - mNativeType = deviceInfo.getPort().type(); } /** @@ -115,14 +109,12 @@ public final class AudioDeviceAttributes implements Parcelable { mRole = role; mType = type; mAddress = address; - mNativeType = AudioSystem.DEVICE_NONE; } /*package*/ AudioDeviceAttributes(int nativeType, @NonNull String address) { mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT; mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType); mAddress = address; - mNativeType = nativeType; } /** @@ -155,15 +147,6 @@ public final class AudioDeviceAttributes implements Parcelable { return mAddress; } - /** - * @hide - * Returns the internal device type of a device - * @return the internal device type - */ - public int getInternalType() { - return mNativeType; - } - @Override public int hashCode() { return Objects.hash(mRole, mType, mAddress); @@ -206,14 +189,12 @@ public final class AudioDeviceAttributes implements Parcelable { dest.writeInt(mRole); dest.writeInt(mType); dest.writeString(mAddress); - dest.writeInt(mNativeType); } private AudioDeviceAttributes(@NonNull Parcel in) { mRole = in.readInt(); mType = in.readInt(); mAddress = in.readString(); - mNativeType = in.readInt(); } public static final @NonNull Parcelable.Creator<AudioDeviceAttributes> CREATOR = diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java index ba880cc58888..d4fb1be56890 100644 --- a/media/java/android/media/AudioDeviceInfo.java +++ b/media/java/android/media/AudioDeviceInfo.java @@ -513,21 +513,10 @@ public final class AudioDeviceInfo { return INT_TO_EXT_DEVICE_MAPPING.get(intDevice, TYPE_UNKNOWN); } - /** @hide */ - public static int convertDeviceTypeToInternalInputDevice(int deviceType) { - return EXT_TO_INT_INPUT_DEVICE_MAPPING.get(deviceType, AudioSystem.DEVICE_NONE); - } - private static final SparseIntArray INT_TO_EXT_DEVICE_MAPPING; private static final SparseIntArray EXT_TO_INT_DEVICE_MAPPING; - /** - * EXT_TO_INT_INPUT_DEVICE_MAPPING aims at mapping external device type to internal input device - * type. - */ - private static final SparseIntArray EXT_TO_INT_INPUT_DEVICE_MAPPING; - static { INT_TO_EXT_DEVICE_MAPPING = new SparseIntArray(); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_EARPIECE, TYPE_BUILTIN_EARPIECE); @@ -612,32 +601,6 @@ public final class AudioDeviceInfo { EXT_TO_INT_DEVICE_MAPPING.put(TYPE_REMOTE_SUBMIX, AudioSystem.DEVICE_OUT_REMOTE_SUBMIX); EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLE_HEADSET, AudioSystem.DEVICE_OUT_BLE_HEADSET); EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLE_SPEAKER, AudioSystem.DEVICE_OUT_BLE_SPEAKER); - - // privileges mapping to input device - EXT_TO_INT_INPUT_DEVICE_MAPPING = new SparseIntArray(); - EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_BUILTIN_MIC, AudioSystem.DEVICE_IN_BUILTIN_MIC); - EXT_TO_INT_INPUT_DEVICE_MAPPING.put( - TYPE_BLUETOOTH_SCO, AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET); - EXT_TO_INT_INPUT_DEVICE_MAPPING.put( - TYPE_WIRED_HEADSET, AudioSystem.DEVICE_IN_WIRED_HEADSET); - EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_HDMI, AudioSystem.DEVICE_IN_HDMI); - EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_TELEPHONY, AudioSystem.DEVICE_IN_TELEPHONY_RX); - EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_DOCK, AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET); - EXT_TO_INT_INPUT_DEVICE_MAPPING.put( - TYPE_USB_ACCESSORY, AudioSystem.DEVICE_IN_USB_ACCESSORY); - EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_USB_DEVICE, AudioSystem.DEVICE_IN_USB_DEVICE); - EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_USB_HEADSET, AudioSystem.DEVICE_IN_USB_HEADSET); - EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_FM_TUNER, AudioSystem.DEVICE_IN_FM_TUNER); - EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_TV_TUNER, AudioSystem.DEVICE_IN_TV_TUNER); - EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_LINE_ANALOG, AudioSystem.DEVICE_IN_LINE); - EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_LINE_DIGITAL, AudioSystem.DEVICE_IN_SPDIF); - EXT_TO_INT_INPUT_DEVICE_MAPPING.put( - TYPE_BLUETOOTH_A2DP, AudioSystem.DEVICE_IN_BLUETOOTH_A2DP); - EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_IP, AudioSystem.DEVICE_IN_IP); - EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_BUS, AudioSystem.DEVICE_IN_BUS); - EXT_TO_INT_INPUT_DEVICE_MAPPING.put( - TYPE_REMOTE_SUBMIX, AudioSystem.DEVICE_IN_REMOTE_SUBMIX); - EXT_TO_INT_INPUT_DEVICE_MAPPING.put(TYPE_BLE_HEADSET, AudioSystem.DEVICE_IN_BLE_HEADSET); } } diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index aa2ff17a307b..a16e063fe969 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -1949,349 +1949,6 @@ public class AudioManager { } //==================================================================== - // Audio Capture Preset routing - - /** - * @hide - * Set the preferred device for a given capture preset, i.e. the audio routing to be used by - * this capture preset. Note that the device may not be available at the time the preferred - * device is set, but it will be used once made available. - * <p>Use {@link #clearPreferredDevicesForCapturePreset(int)} to cancel setting this preference - * for this capture preset.</p> - * @param capturePreset the audio capture preset whose routing will be affected - * @param device the audio device to route to when available - * @return true if the operation was successful, false otherwise - */ - @SystemApi - @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - public boolean setPreferredDeviceForCapturePreset(int capturePreset, - @NonNull AudioDeviceAttributes device) { - return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device)); - } - - /** - * @hide - * Remove all the preferred audio devices previously set - * @param capturePreset the audio capture preset whose routing will be affected - * @return true if the operation was successful, false otherwise (invalid capture preset, or no - * device set for example) - */ - @SystemApi - @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - public boolean clearPreferredDevicesForCapturePreset(int capturePreset) { - if (!MediaRecorder.isValidAudioSource(capturePreset)) { - return false; - } - try { - final int status = getService().clearPreferredDevicesForCapturePreset(capturePreset); - return status == AudioSystem.SUCCESS; - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * @hide - * Return the preferred devices for an audio capture preset, previously set with - * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} - * @param capturePreset the capture preset to query - * @return a list that contains preferred devices for that capture preset. - */ - @NonNull - @SystemApi - @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(int capturePreset) { - if (!MediaRecorder.isValidAudioSource(capturePreset)) { - return new ArrayList<AudioDeviceAttributes>(); - } - try { - return getService().getPreferredDevicesForCapturePreset(capturePreset); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - private boolean setPreferredDevicesForCapturePreset( - int capturePreset, @NonNull List<AudioDeviceAttributes> devices) { - Objects.requireNonNull(devices); - if (!MediaRecorder.isValidAudioSource(capturePreset)) { - return false; - } - if (devices.size() != 1) { - throw new IllegalArgumentException( - "Only support setting one preferred devices for capture preset"); - } - for (AudioDeviceAttributes device : devices) { - Objects.requireNonNull(device); - } - try { - final int status = - getService().setPreferredDevicesForCapturePreset(capturePreset, devices); - return status == AudioSystem.SUCCESS; - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * @hide - * Interface to be notified of changes in the preferred audio devices set for a given capture - * preset. - * <p>Note that this listener will only be invoked whenever - * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} or - * {@link #clearPreferredDevicesForCapturePreset(int)} causes a change in - * preferred device. It will not be invoked directly after registration with - * {@link #addOnPreferredDevicesForCapturePresetChangedListener( - * Executor, OnPreferredDevicesForCapturePresetChangedListener)} - * to indicate which strategies had preferred devices at the time of registration.</p> - * @see #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes) - * @see #clearPreferredDevicesForCapturePreset(int) - * @see #getPreferredDevicesForCapturePreset(int) - */ - @SystemApi - public interface OnPreferredDevicesForCapturePresetChangedListener { - /** - * Called on the listener to indicate that the preferred audio devices for the given - * capture preset has changed. - * @param capturePreset the capture preset whose preferred device changed - * @param devices a list of newly set preferred audio devices - */ - void onPreferredDevicesForCapturePresetChanged( - int capturePreset, @NonNull List<AudioDeviceAttributes> devices); - } - - /** - * @hide - * Adds a listener for being notified of changes to the capture-preset-preferred audio device. - * @param executor - * @param listener - * @throws SecurityException if the caller doesn't hold the required permission - */ - @SystemApi - @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - public void addOnPreferredDevicesForCapturePresetChangedListener( - @NonNull @CallbackExecutor Executor executor, - @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) - throws SecurityException { - Objects.requireNonNull(executor); - Objects.requireNonNull(listener); - int status = addOnDevRoleForCapturePresetChangedListener( - executor, listener, AudioSystem.DEVICE_ROLE_PREFERRED); - if (status == AudioSystem.ERROR) { - // This must not happen - throw new RuntimeException("Unknown error happened"); - } - if (status == AudioSystem.BAD_VALUE) { - throw new IllegalArgumentException( - "attempt to call addOnPreferredDevicesForCapturePresetChangedListener() " - + "on a previously registered listener"); - } - } - - /** - * @hide - * Removes a previously added listener of changes to the capture-preset-preferred audio device. - * @param listener - */ - @SystemApi - @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - public void removeOnPreferredDevicesForCapturePresetChangedListener( - @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) { - Objects.requireNonNull(listener); - int status = removeOnDevRoleForCapturePresetChangedListener( - listener, AudioSystem.DEVICE_ROLE_PREFERRED); - if (status == AudioSystem.ERROR) { - // This must not happen - throw new RuntimeException("Unknown error happened"); - } - if (status == AudioSystem.BAD_VALUE) { - throw new IllegalArgumentException( - "attempt to call removeOnPreferredDevicesForCapturePresetChangedListener() " - + "on an unregistered listener"); - } - } - - private <T> int addOnDevRoleForCapturePresetChangedListener( - @NonNull @CallbackExecutor Executor executor, - @NonNull T listener, int deviceRole) { - Objects.requireNonNull(executor); - Objects.requireNonNull(listener); - DevRoleListeners<T> devRoleListeners = - (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole); - if (devRoleListeners == null) { - return AudioSystem.ERROR; - } - synchronized (devRoleListeners.mDevRoleListenersLock) { - if (devRoleListeners.hasDevRoleListener(listener)) { - return AudioSystem.BAD_VALUE; - } - // lazy initialization of the list of device role listener - if (devRoleListeners.mListenerInfos == null) { - devRoleListeners.mListenerInfos = new ArrayList<>(); - } - final int oldCbCount = devRoleListeners.mListenerInfos.size(); - devRoleListeners.mListenerInfos.add(new DevRoleListenerInfo<T>(executor, listener)); - if (oldCbCount == 0 && devRoleListeners.mListenerInfos.size() > 0) { - // register binder for callbacks - synchronized (mDevRoleForCapturePresetListenersLock) { - int deviceRoleListenerStatus = mDeviceRoleListenersStatus; - mDeviceRoleListenersStatus |= (1 << deviceRole); - if (deviceRoleListenerStatus != 0) { - // There are already device role changed listeners active. - return AudioSystem.SUCCESS; - } - if (mDevicesRoleForCapturePresetDispatcherStub == null) { - mDevicesRoleForCapturePresetDispatcherStub = - new CapturePresetDevicesRoleDispatcherStub(); - } - try { - getService().registerCapturePresetDevicesRoleDispatcher( - mDevicesRoleForCapturePresetDispatcherStub); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - } - } - return AudioSystem.SUCCESS; - } - - private <T> int removeOnDevRoleForCapturePresetChangedListener( - @NonNull T listener, int deviceRole) { - Objects.requireNonNull(listener); - DevRoleListeners<T> devRoleListeners = - (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole); - if (devRoleListeners == null) { - return AudioSystem.ERROR; - } - synchronized (devRoleListeners.mDevRoleListenersLock) { - if (!devRoleListeners.removeDevRoleListener(listener)) { - return AudioSystem.BAD_VALUE; - } - if (devRoleListeners.mListenerInfos.size() == 0) { - // unregister binder for callbacks - synchronized (mDevRoleForCapturePresetListenersLock) { - mDeviceRoleListenersStatus ^= (1 << deviceRole); - if (mDeviceRoleListenersStatus != 0) { - // There are some other device role changed listeners active. - return AudioSystem.SUCCESS; - } - try { - getService().unregisterCapturePresetDevicesRoleDispatcher( - mDevicesRoleForCapturePresetDispatcherStub); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - } - } - return AudioSystem.SUCCESS; - } - - private final Map<Integer, Object> mDevRoleForCapturePresetListeners = new HashMap<>(){{ - put(AudioSystem.DEVICE_ROLE_PREFERRED, - new DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>()); - }}; - - private class DevRoleListenerInfo<T> { - final @NonNull Executor mExecutor; - final @NonNull T mListener; - DevRoleListenerInfo(Executor executor, T listener) { - mExecutor = executor; - mListener = listener; - } - } - - private class DevRoleListeners<T> { - private final Object mDevRoleListenersLock = new Object(); - @GuardedBy("mDevRoleListenersLock") - private @Nullable ArrayList<DevRoleListenerInfo<T>> mListenerInfos; - - @GuardedBy("mDevRoleListenersLock") - private @Nullable DevRoleListenerInfo<T> getDevRoleListenerInfo(T listener) { - if (mListenerInfos == null) { - return null; - } - for (DevRoleListenerInfo<T> listenerInfo : mListenerInfos) { - if (listenerInfo.mListener == listener) { - return listenerInfo; - } - } - return null; - } - - @GuardedBy("mDevRoleListenersLock") - private boolean hasDevRoleListener(T listener) { - return getDevRoleListenerInfo(listener) != null; - } - - @GuardedBy("mDevRoleListenersLock") - private boolean removeDevRoleListener(T listener) { - final DevRoleListenerInfo<T> infoToRemove = getDevRoleListenerInfo(listener); - if (infoToRemove != null) { - mListenerInfos.remove(infoToRemove); - return true; - } - return false; - } - } - - private final Object mDevRoleForCapturePresetListenersLock = new Object(); - /** - * Record if there is a listener added for device role change. If there is a listener added for - * a specified device role change, the bit at position `1 << device_role` is set. - */ - @GuardedBy("mDevRoleForCapturePresetListenersLock") - private int mDeviceRoleListenersStatus = 0; - @GuardedBy("mDevRoleForCapturePresetListenersLock") - private CapturePresetDevicesRoleDispatcherStub mDevicesRoleForCapturePresetDispatcherStub; - - private final class CapturePresetDevicesRoleDispatcherStub - extends ICapturePresetDevicesRoleDispatcher.Stub { - - @Override - public void dispatchDevicesRoleChanged( - int capturePreset, int role, List<AudioDeviceAttributes> devices) { - final Object listenersObj = mDevRoleForCapturePresetListeners.get(role); - if (listenersObj == null) { - return; - } - switch (role) { - case AudioSystem.DEVICE_ROLE_PREFERRED: { - final DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener> - listeners = - (DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>) - listenersObj; - final ArrayList<DevRoleListenerInfo< - OnPreferredDevicesForCapturePresetChangedListener>> prefDevListeners; - synchronized (listeners.mDevRoleListenersLock) { - if (listeners.mListenerInfos.isEmpty()) { - return; - } - prefDevListeners = (ArrayList<DevRoleListenerInfo< - OnPreferredDevicesForCapturePresetChangedListener>>) - listeners.mListenerInfos.clone(); - } - final long ident = Binder.clearCallingIdentity(); - try { - for (DevRoleListenerInfo< - OnPreferredDevicesForCapturePresetChangedListener> info : - prefDevListeners) { - info.mExecutor.execute(() -> - info.mListener.onPreferredDevicesForCapturePresetChanged( - capturePreset, devices)); - } - } finally { - Binder.restoreCallingIdentity(ident); - } - } break; - default: - break; - } - } - } - - //==================================================================== // Offload query /** * Returns whether offloaded playback of an audio format is supported on the device. diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 279ba0a55be0..22f625004aaf 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -27,7 +27,6 @@ import android.media.audiofx.AudioEffect; import android.media.audiopolicy.AudioMix; import android.telephony.TelephonyManager; import android.util.Log; -import android.util.Pair; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -1756,134 +1755,6 @@ public class AudioSystem public static native int getDevicesForRoleAndStrategy( int strategy, int role, @NonNull List<AudioDeviceAttributes> devices); - // use case routing by capture preset - - private static Pair<int[], String[]> populateInputDevicesTypeAndAddress( - @NonNull List<AudioDeviceAttributes> devices) { - int[] types = new int[devices.size()]; - String[] addresses = new String[devices.size()]; - for (int i = 0; i < devices.size(); ++i) { - types[i] = devices.get(i).getInternalType(); - if (types[i] == AudioSystem.DEVICE_NONE) { - types[i] = AudioDeviceInfo.convertDeviceTypeToInternalInputDevice( - devices.get(i).getType()); - } - addresses[i] = devices.get(i).getAddress(); - } - return new Pair<int[], String[]>(types, addresses); - } - - /** - * @hide - * Set devices as role for capture preset. - * @param capturePreset the capture preset to configure - * @param role the role of the devices - * @param devices the list of devices to be set as role for the given capture preset - * @return {@link #SUCCESS} if successfully set - */ - public static int setDevicesRoleForCapturePreset( - int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) { - if (devices.isEmpty()) { - return BAD_VALUE; - } - Pair<int[], String[]> typeAddresses = populateInputDevicesTypeAndAddress(devices); - return setDevicesRoleForCapturePreset( - capturePreset, role, typeAddresses.first, typeAddresses.second); - } - - /** - * @hide - * Set devices as role for capture preset. - * @param capturePreset the capture preset to configure - * @param role the role of the devices - * @param types all device types - * @param addresses all device addresses - * @return {@link #SUCCESS} if successfully set - */ - private static native int setDevicesRoleForCapturePreset( - int capturePreset, int role, @NonNull int[] types, @NonNull String[] addresses); - - /** - * @hide - * Add devices as role for capture preset. - * @param capturePreset the capture preset to configure - * @param role the role of the devices - * @param devices the list of devices to be added as role for the given capture preset - * @return {@link #SUCCESS} if successfully add - */ - public static int addDevicesRoleForCapturePreset( - int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) { - if (devices.isEmpty()) { - return BAD_VALUE; - } - Pair<int[], String[]> typeAddresses = populateInputDevicesTypeAndAddress(devices); - return addDevicesRoleForCapturePreset( - capturePreset, role, typeAddresses.first, typeAddresses.second); - } - - /** - * @hide - * Add devices as role for capture preset. - * @param capturePreset the capture preset to configure - * @param role the role of the devices - * @param types all device types - * @param addresses all device addresses - * @return {@link #SUCCESS} if successfully set - */ - private static native int addDevicesRoleForCapturePreset( - int capturePreset, int role, @NonNull int[] types, @NonNull String[] addresses); - - /** - * @hide - * Remove devices as role for the capture preset - * @param capturePreset the capture preset to configure - * @param role the role of the devices - * @param devices the devices to be removed - * @return {@link #SUCCESS} if successfully removed - */ - public static int removeDevicesRoleForCapturePreset( - int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) { - if (devices.isEmpty()) { - return BAD_VALUE; - } - Pair<int[], String[]> typeAddresses = populateInputDevicesTypeAndAddress(devices); - return removeDevicesRoleForCapturePreset( - capturePreset, role, typeAddresses.first, typeAddresses.second); - } - - /** - * @hide - * Remove devices as role for capture preset. - * @param capturePreset the capture preset to configure - * @param role the role of the devices - * @param types all device types - * @param addresses all device addresses - * @return {@link #SUCCESS} if successfully set - */ - private static native int removeDevicesRoleForCapturePreset( - int capturePreset, int role, @NonNull int[] types, @NonNull String[] addresses); - - /** - * @hide - * Remove all devices as role for the capture preset - * @param capturePreset the capture preset to configure - * @param role the role of the devices - * @return {@link #SUCCESS} if successfully removed - */ - public static native int clearDevicesRoleForCapturePreset(int capturePreset, int role); - - /** - * @hide - * Query previously set devices as role for a capture preset - * @param capturePreset the capture preset to query for - * @param role the role of the devices - * @param devices a list that will contain the devices of role - * @return {@link #SUCCESS} if there is a preferred device and it was successfully retrieved - * and written to the array - */ - public static native int getDevicesForRoleAndCapturePreset( - int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices); - // Items shared with audio service /** diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 85fb67df82d4..ef8b0edb1fe5 100755 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -26,7 +26,6 @@ import android.media.AudioRoutesInfo; import android.media.IAudioFocusDispatcher; import android.media.IAudioRoutesObserver; import android.media.IAudioServerStateDispatcher; -import android.media.ICapturePresetDevicesRoleDispatcher; import android.media.IPlaybackConfigDispatcher; import android.media.IRecordingConfigDispatcher; import android.media.IRingtonePlayer; @@ -308,16 +307,4 @@ interface IAudioService { // code via IAudioManager.h need to be added to the top section. oneway void setMultiAudioFocusEnabled(in boolean enabled); - - int setPreferredDevicesForCapturePreset( - in int capturePreset, in List<AudioDeviceAttributes> devices); - - int clearPreferredDevicesForCapturePreset(in int capturePreset); - - List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(in int capturePreset); - - void registerCapturePresetDevicesRoleDispatcher(ICapturePresetDevicesRoleDispatcher dispatcher); - - oneway void unregisterCapturePresetDevicesRoleDispatcher( - ICapturePresetDevicesRoleDispatcher dispatcher); } diff --git a/media/java/android/media/ICapturePresetDevicesRoleDispatcher.aidl b/media/java/android/media/ICapturePresetDevicesRoleDispatcher.aidl deleted file mode 100644 index 5e03e632c4ff..000000000000 --- a/media/java/android/media/ICapturePresetDevicesRoleDispatcher.aidl +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.media; - -import android.media.AudioDeviceAttributes; - -/** - * AIDL for AudioService to signal devices role for capture preset updates. - * - * {@hide} - */ -oneway interface ICapturePresetDevicesRoleDispatcher { - - void dispatchDevicesRoleChanged( - int capturePreset, int role, in List<AudioDeviceAttributes> devices); - -} diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 1db02beaea1a..4198d7917932 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -404,32 +404,6 @@ public class MediaRecorder implements AudioRouting, } } - /** - * @hide - * @param source An audio source to test - * @return true if the source is a valid one - */ - public static boolean isValidAudioSource(int source) { - switch(source) { - case AudioSource.MIC: - case AudioSource.VOICE_UPLINK: - case AudioSource.VOICE_DOWNLINK: - case AudioSource.VOICE_CALL: - case AudioSource.CAMCORDER: - case AudioSource.VOICE_RECOGNITION: - case AudioSource.VOICE_COMMUNICATION: - case AudioSource.REMOTE_SUBMIX: - case AudioSource.UNPROCESSED: - case AudioSource.VOICE_PERFORMANCE: - case AudioSource.ECHO_REFERENCE: - case AudioSource.RADIO_TUNER: - case AudioSource.HOTWORD: - return true; - default: - return false; - } - } - /** @hide */ public static final String toLogFriendlyAudioSource(int source) { switch(source) { diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java index aa57233bc824..24dacc48f28e 100644 --- a/media/java/android/media/session/MediaController.java +++ b/media/java/android/media/session/MediaController.java @@ -16,8 +16,11 @@ package android.media.session; +import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.app.PendingIntent; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; @@ -27,6 +30,7 @@ import android.media.AudioManager; import android.media.MediaMetadata; import android.media.Rating; import android.media.VolumeProvider; +import android.media.VolumeProvider.ControlType; import android.media.session.MediaSession.QueueItem; import android.net.Uri; import android.os.Bundle; @@ -41,6 +45,8 @@ import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; @@ -950,6 +956,14 @@ public final class MediaController { * this session. */ public static final class PlaybackInfo implements Parcelable { + + /** + * @hide + */ + @IntDef({PLAYBACK_TYPE_LOCAL, PLAYBACK_TYPE_REMOTE}) + @Retention(RetentionPolicy.SOURCE) + public @interface PlaybackType {} + /** * The session uses local playback. */ @@ -959,7 +973,7 @@ public final class MediaController { */ public static final int PLAYBACK_TYPE_REMOTE = 2; - private final int mVolumeType; + private final int mPlaybackType; private final int mVolumeControl; private final int mMaxVolume; private final int mCurrentVolume; @@ -967,27 +981,35 @@ public final class MediaController { private final String mVolumeControlId; /** + * Creates a new playback info. + * + * @param playbackType The playback type. Should be {@link #PLAYBACK_TYPE_LOCAL} or + * {@link #PLAYBACK_TYPE_REMOTE} + * @param volumeControl The volume control. Should be one of: + * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}, + * {@link VolumeProvider#VOLUME_CONTROL_RELATIVE}, and + * {@link VolumeProvider#VOLUME_CONTROL_FIXED}. + * @param maxVolume The max volume. Should be equal or greater than zero. + * @param currentVolume The current volume. Should be in the interval [0, maxVolume]. + * @param audioAttrs The audio attributes for this playback. Should not be null. + * @param volumeControlId The volume control ID. This is used for matching + * {@link RoutingSessionInfo} and {@link MediaSession}. * @hide */ - public PlaybackInfo(int type, int control, int max, int current, AudioAttributes attrs) { - this(type, control, max, current, attrs, null); - } - - /** - * @hide - */ - public PlaybackInfo(int type, int control, int max, int current, AudioAttributes attrs, - String volumeControlId) { - mVolumeType = type; - mVolumeControl = control; - mMaxVolume = max; - mCurrentVolume = current; - mAudioAttrs = attrs; + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public PlaybackInfo(@PlaybackType int playbackType, @ControlType int volumeControl, + @IntRange(from = 0) int maxVolume, @IntRange(from = 0) int currentVolume, + @NonNull AudioAttributes audioAttrs, @Nullable String volumeControlId) { + mPlaybackType = playbackType; + mVolumeControl = volumeControl; + mMaxVolume = maxVolume; + mCurrentVolume = currentVolume; + mAudioAttrs = audioAttrs; mVolumeControlId = volumeControlId; } PlaybackInfo(Parcel in) { - mVolumeType = in.readInt(); + mPlaybackType = in.readInt(); mVolumeControl = in.readInt(); mMaxVolume = in.readInt(); mCurrentVolume = in.readInt(); @@ -1005,7 +1027,7 @@ public final class MediaController { * @return The type of playback this session is using. */ public int getPlaybackType() { - return mVolumeType; + return mPlaybackType; } /** @@ -1016,8 +1038,7 @@ public final class MediaController { * <li>{@link VolumeProvider#VOLUME_CONTROL_FIXED}</li> * </ul> * - * @return The type of volume control that may be used with this - * session. + * @return The type of volume control that may be used with this session. */ public int getVolumeControl() { return mVolumeControl; @@ -1075,7 +1096,7 @@ public final class MediaController { @Override public String toString() { - return "volumeType=" + mVolumeType + ", volumeControl=" + mVolumeControl + return "playbackType=" + mPlaybackType + ", volumeControlType=" + mVolumeControl + ", maxVolume=" + mMaxVolume + ", currentVolume=" + mCurrentVolume + ", audioAttrs=" + mAudioAttrs + ", volumeControlId=" + mVolumeControlId; } @@ -1087,7 +1108,7 @@ public final class MediaController { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mVolumeType); + dest.writeInt(mPlaybackType); dest.writeInt(mVolumeControl); dest.writeInt(mMaxVolume); dest.writeInt(mCurrentVolume); diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt index b20e6712be61..d4c5e7ea375d 100644 --- a/non-updatable-api/module-lib-current.txt +++ b/non-updatable-api/module-lib-current.txt @@ -42,6 +42,10 @@ package android.media { package android.media.session { + public static final class MediaController.PlaybackInfo implements android.os.Parcelable { + ctor public MediaController.PlaybackInfo(int, int, @IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.media.AudioAttributes, @Nullable String); + } + public final class MediaSession { field public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 65536; // 0x10000 } diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt index 024f4acd8940..cc6c3dc97acf 100644 --- a/non-updatable-api/system-current.txt +++ b/non-updatable-api/system-current.txt @@ -4139,10 +4139,8 @@ package android.media { public class AudioManager { method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDeviceForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener) throws java.lang.SecurityException; - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForCapturePresetChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener) throws java.lang.SecurityException; method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener) throws java.lang.SecurityException; method public void clearAudioServerStateCallback(); - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean clearPreferredDevicesForCapturePreset(int); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); method @IntRange(from=0) public long getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioProductStrategy> getAudioProductStrategies(); @@ -4153,7 +4151,6 @@ package android.media { method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioDeviceAttributes getPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); - method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getPreferredDevicesForCapturePreset(int); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int[] getSupportedSystemUsages(); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); @@ -4162,7 +4159,6 @@ package android.media { method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); method public void registerVolumeGroupCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.VolumeGroupCallback); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDeviceForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener); - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForCapturePresetChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForCapturePresetChangedListener); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean removePreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException; @@ -4172,7 +4168,6 @@ package android.media { method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForCapturePreset(int, @NonNull android.media.AudioDeviceAttributes); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setSupportedSystemUsages(@NonNull int[]); @@ -4202,10 +4197,6 @@ package android.media { method @Deprecated public void onPreferredDeviceForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @Nullable android.media.AudioDeviceAttributes); } - public static interface AudioManager.OnPreferredDevicesForCapturePresetChangedListener { - method public void onPreferredDevicesForCapturePresetChanged(int, @NonNull java.util.List<android.media.AudioDeviceAttributes>); - } - public static interface AudioManager.OnPreferredDevicesForStrategyChangedListener { method public void onPreferredDevicesForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>); } diff --git a/packages/CarSystemUI/res/drawable/hvac_decrease_button.xml b/packages/CarSystemUI/res/drawable/hvac_decrease_button.xml index 469ac91073f9..656e94ae348b 100644 --- a/packages/CarSystemUI/res/drawable/hvac_decrease_button.xml +++ b/packages/CarSystemUI/res/drawable/hvac_decrease_button.xml @@ -27,20 +27,20 @@ android:width="@dimen/system_bar_icon_drawing_size" android:height="@dimen/system_bar_icon_drawing_size"/> <solid - android:color="#3C4043"/> + android:color="@color/hvac_temperature_adjust_button_color"/> </shape> </aapt:attr> </item> <item android:gravity="center" - android:width="48dp" - android:height="48dp"> + android:width="@dimen/system_bar_icon_drawing_size" + android:height="@dimen/system_bar_icon_drawing_size"> <aapt:attr name="android:drawable"> - <vector android:width="48dp" - android:height="48dp" + <vector android:width="@dimen/system_bar_icon_drawing_size" + android:height="@dimen/system_bar_icon_drawing_size" android:viewportWidth="24.0" android:viewportHeight="24.0"> <path - android:fillColor="#8AB4F8" + android:fillColor="@color/hvac_temperature_decrease_arrow_color" android:pathData="M14,7l-5,5 5,5V7z"/> </vector> </aapt:attr> diff --git a/packages/CarSystemUI/res/drawable/hvac_increase_button.xml b/packages/CarSystemUI/res/drawable/hvac_increase_button.xml index a3fca2233ddd..57c07c873d76 100644 --- a/packages/CarSystemUI/res/drawable/hvac_increase_button.xml +++ b/packages/CarSystemUI/res/drawable/hvac_increase_button.xml @@ -27,20 +27,20 @@ android:width="@dimen/system_bar_icon_drawing_size" android:height="@dimen/system_bar_icon_drawing_size"/> <solid - android:color="#3C4043"/> + android:color="@color/hvac_temperature_adjust_button_color"/> </shape> </aapt:attr> </item> <item android:gravity="center" - android:width="48dp" - android:height="48dp"> + android:width="@dimen/system_bar_icon_drawing_size" + android:height="@dimen/system_bar_icon_drawing_size"> <aapt:attr name="android:drawable"> - <vector android:width="48dp" - android:height="48dp" + <vector android:width="@dimen/system_bar_icon_drawing_size" + android:height="@dimen/system_bar_icon_drawing_size" android:viewportWidth="24.0" android:viewportHeight="24.0"> <path - android:fillColor="#F28B82" + android:fillColor="@color/hvac_temperature_increase_arrow_color" android:pathData="M10,17l5,-5 -5,-5v10z"/> </vector> </aapt:attr> 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 d9c149106451..b8ac2b43b047 100644 --- a/packages/CarSystemUI/res/layout/car_top_navigation_bar_unprovisioned.xml +++ b/packages/CarSystemUI/res/layout/car_top_navigation_bar_unprovisioned.xml @@ -56,8 +56,6 @@ android:textAppearance="@style/TextAppearance.CarStatus" systemui:hvacAreaId="49" systemui:hvacPivotOffset="60dp" - systemui:hvacPropertyId="358614275" - systemui:hvacTempFormat="%.0f\u00B0" /> </FrameLayout> @@ -130,8 +128,6 @@ android:textAppearance="@style/TextAppearance.CarStatus" systemui:hvacAreaId="68" systemui:hvacPivotOffset="60dp" - systemui:hvacPropertyId="358614275" - systemui:hvacTempFormat="%.0f\u00B0" /> </FrameLayout> </RelativeLayout> diff --git a/packages/CarSystemUI/res/values/colors.xml b/packages/CarSystemUI/res/values/colors.xml index 1e15affcbf48..c390cc8d70a4 100644 --- a/packages/CarSystemUI/res/values/colors.xml +++ b/packages/CarSystemUI/res/values/colors.xml @@ -37,6 +37,11 @@ <color name="status_bar_background_color">#33000000</color> <drawable name="system_bar_background">@color/status_bar_background_color</drawable> + <!-- colors for hvac temperature view --> + <color name="hvac_temperature_adjust_button_color">#3C4043</color> + <color name="hvac_temperature_decrease_arrow_color">#8AB4F8</color> + <color name="hvac_temperature_increase_arrow_color">#F28B82</color> + <!-- The background color of the notification shade --> <color name="notification_shade_background_color">#D6000000</color> diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml index f02a8e7648c0..28b8eadf9750 100644 --- a/packages/CarSystemUI/res/values/dimens.xml +++ b/packages/CarSystemUI/res/values/dimens.xml @@ -48,8 +48,14 @@ <dimen name="system_bar_user_icon_padding">16dp</dimen> <dimen name="system_bar_user_icon_drawing_size">36dp</dimen> + <!-- Padding on either side of the group of all system bar buttons --> <dimen name="system_bar_button_group_padding">64dp</dimen> <dimen name="system_bar_icon_drawing_size">44dp</dimen> + <dimen name="system_bar_button_size">76dp</dimen> + <!-- Margin between the system bar buttons --> + <dimen name="system_bar_button_margin">32dp</dimen> + <!-- Padding between the system bar button and the icon within it --> + <dimen name="system_bar_button_padding">16dp</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> @@ -61,8 +67,8 @@ <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_celsius" format="float" type="dimen">0</item> - <item name="hvac_max_value_celsius" format="float" type="dimen">126</item> + <item name="hvac_min_value_celsius" format="float" type="dimen">10</item> + <item name="hvac_max_value_celsius" format="float" type="dimen">35</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/styles.xml b/packages/CarSystemUI/res/values/styles.xml index 0db17ac42a77..f242db0aec09 100644 --- a/packages/CarSystemUI/res/values/styles.xml +++ b/packages/CarSystemUI/res/values/styles.xml @@ -43,10 +43,10 @@ </style> <style name="NavigationBarButton"> - <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:layout_height">@dimen/system_bar_button_size</item> + <item name="android:layout_width">@dimen/system_bar_button_size</item> + <item name="android:layout_marginEnd">@dimen/system_bar_button_margin</item> + <item name="android:padding">@dimen/system_bar_button_padding</item> <item name="android:gravity">center</item> <item name="android:background">?android:attr/selectableItemBackground</item> </style> diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java index 4cac4456789d..85d4ceb81eeb 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java @@ -35,22 +35,27 @@ import com.android.systemui.R; */ public class AdjustableTemperatureView extends LinearLayout implements TemperatureView { - private HvacController mHvacController; - private float mCurrentTempC; + private final int mAreaId; private TextView mTempTextView; + private float mMinTempC; + private float mMaxTempC; + private String mTempFormat; private boolean mDisplayInFahrenheit = false; - private final float mMinTempC; - private final float mMaxTempC; - private final int mAreaId; - private final String mTempFormat; + private HvacController mHvacController; + private float mCurrentTempC; 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); + @Override + public void onFinishInflate() { + super.onFinishInflate(); + LayoutInflater.from(getContext()).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); @@ -63,7 +68,7 @@ public class AdjustableTemperatureView extends LinearLayout implements Temperatu } @Override - public void setTemperatureView(float tempC) { + public void setTemp(float tempC) { if (tempC > mMaxTempC || tempC < mMinTempC) { return; } @@ -78,7 +83,7 @@ public class AdjustableTemperatureView extends LinearLayout implements Temperatu @Override public void setDisplayInFahrenheit(boolean displayFahrenheit) { mDisplayInFahrenheit = displayFahrenheit; - setTemperatureView(mCurrentTempC); + setTemp(mCurrentTempC); } @Override 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 567baa91cb59..b98b68038e6f 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/AnimatedTemperatureView.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/AnimatedTemperatureView.java @@ -189,7 +189,7 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV * @param temp - The current temp or NaN */ @Override - public void setTemperatureView(float temp) { + public void setTemp(float temp) { if (mDisplayInFahrenheit) { temp = convertToFahrenheit(temp); } 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 f7451dc6fdee..10a361c3084e 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java @@ -30,6 +30,7 @@ import android.view.ViewGroup; import com.android.systemui.car.CarServiceProvider; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.UiBackground; import java.util.ArrayList; import java.util.HashMap; @@ -37,6 +38,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.Executor; import javax.inject.Inject; @@ -49,6 +51,7 @@ public class HvacController { public static final String TAG = "HvacController"; private static final boolean DEBUG = true; + private final Executor mBackgroundExecutor; private final CarServiceProvider mCarServiceProvider; private final Set<TemperatureView> mRegisteredViews = new HashSet<>(); @@ -68,7 +71,7 @@ public class HvacController { Log.d(TAG, "onChangeEvent: " + areaId + ":" + value); } for (TemperatureView view : temperatureViews) { - view.setTemperatureView(newTemp); + view.setTemp(newTemp); } } } catch (Exception e) { @@ -117,8 +120,10 @@ public class HvacController { }; @Inject - public HvacController(CarServiceProvider carServiceProvider) { + public HvacController(CarServiceProvider carServiceProvider, + @UiBackground Executor backgroundExecutor) { mCarServiceProvider = carServiceProvider; + mBackgroundExecutor = backgroundExecutor; } /** @@ -171,14 +176,14 @@ public class HvacController { } if (mCarPropertyManager == null || !mCarPropertyManager.isPropertyAvailable( HVAC_TEMPERATURE_SET, zone)) { - view.setTemperatureView(Float.NaN); + view.setTemp(Float.NaN); return; } - view.setTemperatureView( + view.setTemp( mCarPropertyManager.getFloatProperty(HVAC_TEMPERATURE_SET, zone)); view.setHvacController(this); } catch (Exception e) { - view.setTemperatureView(Float.NaN); + view.setTemp(Float.NaN); Log.e(TAG, "Failed to get value from hvac service", e); } } @@ -213,7 +218,8 @@ public class HvacController { 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); + mBackgroundExecutor.execute( + () -> mCarPropertyManager.setFloatProperty(HVAC_TEMPERATURE_SET, zone, tempC)); } } @@ -234,6 +240,6 @@ public class HvacController { * @return Temperature in Celsius. */ public static float convertToCelsius(float tempF) { - return (float) ((tempF - 32) * 0.55555555556); + return (tempF - 32) * 5f / 9f; } } 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 252f7830b72c..90df15c907dd 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextView.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextView.java @@ -56,7 +56,7 @@ public class TemperatureTextView extends TextView implements TemperatureView { * @param temp - The current temp or NaN */ @Override - public void setTemperatureView(float temp) { + public void setTemp(float temp) { if (Float.isNaN(temp)) { setText("--"); return; 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 3c0e0acc446c..6edf25431ffd 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureView.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureView.java @@ -33,7 +33,7 @@ public interface TemperatureView { * * @param temp - The current temp in Celsius or NaN */ - void setTemperatureView(float temp); + void setTemp(float temp); /** * Render the displayed temperature in Fahrenheit 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 index e8850def6bcd..a3a55aae5f18 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java @@ -46,9 +46,12 @@ 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; +import java.util.concurrent.Executor; + @CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -64,6 +67,8 @@ public class AdjustableTemperatureViewTest extends SysuiTestCase { private Car mCar; @Mock private CarPropertyManager mCarPropertyManager; + @Mock + private Executor mExecutor; @Before public void setUp() { @@ -72,9 +77,10 @@ public class AdjustableTemperatureViewTest extends SysuiTestCase { when(mCar.getCarManager(Car.PROPERTY_SERVICE)).thenReturn(mCarPropertyManager); CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar); - mHvacController = new HvacController(carServiceProvider); + mHvacController = new HvacController(carServiceProvider, mExecutor); mHvacController.connectToCarService(); mAdjustableTemperatureView = new AdjustableTemperatureView(getContext(), /* attrs= */ null); + mAdjustableTemperatureView.onFinishInflate(); mAdjustableTemperatureView.setHvacController(mHvacController); } @@ -118,6 +124,9 @@ public class AdjustableTemperatureViewTest extends SysuiTestCase { mAdjustableTemperatureView.findViewById(R.id.hvac_increase_button).callOnClick(); + ArgumentCaptor<Runnable> setTempRunnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mExecutor).execute(setTempRunnableCaptor.capture()); + setTempRunnableCaptor.getValue().run(); verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(), eq(TEMP_CELSIUS + 1)); } @@ -132,6 +141,9 @@ public class AdjustableTemperatureViewTest extends SysuiTestCase { mAdjustableTemperatureView.findViewById(R.id.hvac_decrease_button).callOnClick(); + ArgumentCaptor<Runnable> setTempRunnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mExecutor).execute(setTempRunnableCaptor.capture()); + setTempRunnableCaptor.getValue().run(); verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(), eq(TEMP_CELSIUS - 1)); } @@ -150,6 +162,9 @@ public class AdjustableTemperatureViewTest extends SysuiTestCase { mAdjustableTemperatureView.findViewById(R.id.hvac_increase_button).callOnClick(); + ArgumentCaptor<Runnable> setTempRunnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mExecutor).execute(setTempRunnableCaptor.capture()); + setTempRunnableCaptor.getValue().run(); verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(), eq(convertToCelsius(convertToFahrenheit(TEMP_CELSIUS) + 1))); } @@ -168,6 +183,9 @@ public class AdjustableTemperatureViewTest extends SysuiTestCase { mAdjustableTemperatureView.findViewById(R.id.hvac_decrease_button).callOnClick(); + ArgumentCaptor<Runnable> setTempRunnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mExecutor).execute(setTempRunnableCaptor.capture()); + setTempRunnableCaptor.getValue().run(); 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 9912657d78e1..52f07dfd6b81 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 @@ -40,6 +40,8 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.car.CarServiceProvider; import com.android.systemui.car.CarSystemUiTest; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; @@ -70,7 +72,8 @@ public class HvacControllerTest extends SysuiTestCase { when(mCar.getCarManager(Car.PROPERTY_SERVICE)).thenReturn(mCarPropertyManager); CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar); - mHvacController = new HvacController(carServiceProvider); + mHvacController = new HvacController(carServiceProvider, + new FakeExecutor(new FakeSystemClock())); mHvacController.connectToCarService(); } @@ -86,31 +89,31 @@ public class HvacControllerTest extends SysuiTestCase { TemperatureTextView v = setupMockTemperatureTextView(AREA_ID, TEMP); mHvacController.addTemperatureViewToController(v); - verify(v).setTemperatureView(TEMP); + verify(v).setTemp(TEMP); } @Test public void addTemperatureViewToController_usingSameTemperatureView_registersFirstView() { TemperatureTextView v = setupMockTemperatureTextView(AREA_ID, TEMP); mHvacController.addTemperatureViewToController(v); - verify(v).setTemperatureView(TEMP); + verify(v).setTemp(TEMP); resetTemperatureView(v, AREA_ID); mHvacController.addTemperatureViewToController(v); - verify(v, never()).setTemperatureView(TEMP); + verify(v, never()).setTemp(TEMP); } @Test public void addTemperatureViewToController_usingDifferentTemperatureView_registersBothViews() { TemperatureTextView v1 = setupMockTemperatureTextView(AREA_ID, TEMP); mHvacController.addTemperatureViewToController(v1); - verify(v1).setTemperatureView(TEMP); + verify(v1).setTemp(TEMP); TemperatureTextView v2 = setupMockTemperatureTextView( AREA_ID + 1, TEMP + 1); mHvacController.addTemperatureViewToController(v2); - verify(v2).setTemperatureView(TEMP + 1); + verify(v2).setTemp(TEMP + 1); } @Test @@ -124,7 +127,7 @@ public class HvacControllerTest extends SysuiTestCase { mHvacController.addTemperatureViewToController(v); verify(v).setDisplayInFahrenheit(true); - verify(v).setTemperatureView(TEMP); + verify(v).setTemp(TEMP); } private TemperatureTextView setupMockTemperatureTextView(int areaId, float value) { 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 index e97d9d9b3f6a..3ed811105a54 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/TemperatureTextViewTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/TemperatureTextViewTest.java @@ -40,6 +40,8 @@ import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.car.CarServiceProvider; import com.android.systemui.car.CarSystemUiTest; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; @@ -72,7 +74,8 @@ public class TemperatureTextViewTest extends SysuiTestCase { when(mCar.getCarManager(Car.PROPERTY_SERVICE)).thenReturn(mCarPropertyManager); CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar); - mHvacController = new HvacController(carServiceProvider); + mHvacController = new HvacController(carServiceProvider, + new FakeExecutor(new FakeSystemClock())); mHvacController.connectToCarService(); mTextView = new TemperatureTextView(getContext(), /* attrs= */ null); } diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index dcdadbdf3454..4a11aa77c7fc 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -400,7 +400,7 @@ <string name="inactive_app_active_summary" msgid="8047630990208722344">"Aktibo. Aldatzeko, sakatu hau."</string> <string name="standby_bucket_summary" msgid="5128193447550429600">"Egonean moduko aplikazioaren egoera: <xliff:g id="BUCKET"> %s</xliff:g>"</string> <string name="runningservices_settings_title" msgid="6460099290493086515">"Abian diren zerbitzuak"</string> - <string name="runningservices_settings_summary" msgid="1046080643262665743">"Ikusi eta kontrolatu unean abian diren zerbitzuak"</string> + <string name="runningservices_settings_summary" msgid="1046080643262665743">"Ikusi eta kontrolatu une honetan abian diren zerbitzuak"</string> <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView inplementazioa"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Ezarri WebView inplementazioa"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Jada ez dago erabilgarri aukera hori. Saiatu berriro."</string> diff --git a/packages/SettingsLib/res/values-ja/arrays.xml b/packages/SettingsLib/res/values-ja/arrays.xml index 743017c82e3a..7a4e71b18ec0 100644 --- a/packages/SettingsLib/res/values-ja/arrays.xml +++ b/packages/SettingsLib/res/values-ja/arrays.xml @@ -243,7 +243,7 @@ </string-array> <string-array name="track_frame_time_entries"> <item msgid="634406443901014984">"OFF"</item> - <item msgid="1288760936356000927">"バーとして画面に表示"</item> + <item msgid="1288760936356000927">"棒グラフとして画面に表示"</item> <item msgid="5023908510820531131">"<xliff:g id="AS_TYPED_COMMAND">adb shell dumpsys gfxinfo</xliff:g> 内"</item> </string-array> <string-array name="debug_hw_overdraw_entries"> diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml index c4b5f7e7477f..419c18f3b8c6 100644 --- a/packages/SettingsLib/res/values-ky/strings.xml +++ b/packages/SettingsLib/res/values-ky/strings.xml @@ -396,8 +396,8 @@ <item msgid="1282170165150762976">"Санарип мазмун үчүн оптималдаштырылган түстөр"</item> </string-array> <string name="inactive_apps_title" msgid="5372523625297212320">"Көшүү режиминдеги колдонмолор"</string> - <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"Иштеген жок. Которуштуруу үчүн таптап коюңуз."</string> - <string name="inactive_app_active_summary" msgid="8047630990208722344">"Иштеп турат. Которуштуруу үчүн таптап коюңуз."</string> + <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"Иштеген жок. Күйгүзүү үчүн басып коюңуз."</string> + <string name="inactive_app_active_summary" msgid="8047630990208722344">"Иштеп турат. Өчүрүү үчүн басып коюңуз."</string> <string name="standby_bucket_summary" msgid="5128193447550429600">"Көшүү режиминдеги колдонмонун абалы:<xliff:g id="BUCKET"> %s</xliff:g>"</string> <string name="runningservices_settings_title" msgid="6460099290493086515">"Иштеп жаткан кызматтар"</string> <string name="runningservices_settings_summary" msgid="1046080643262665743">"Учурда иштеп жаткан кызматтарды көрүп, көзөмөлдөп турасыз"</string> diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml index fb7b63410a5f..58d4af1c2c64 100644 --- a/packages/SettingsLib/res/values-mk/strings.xml +++ b/packages/SettingsLib/res/values-mk/strings.xml @@ -204,10 +204,10 @@ <string name="tethering_settings_not_available" msgid="266821736434699780">"Поставките за спојување не се достапни за овој корисник"</string> <string name="apn_settings_not_available" msgid="1147111671403342300">"Поставките за името на пристапната точка не се достапни за овој корисник"</string> <string name="enable_adb" msgid="8072776357237289039">"Отстранување грешки на USB"</string> - <string name="enable_adb_summary" msgid="3711526030096574316">"Режим на отстранување грешки кога е поврзано USB"</string> + <string name="enable_adb_summary" msgid="3711526030096574316">"Режим за отстранување грешки кога е поврзано USB"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"Отповикај овластувања за отстранување грешки од USB"</string> <string name="enable_adb_wireless" msgid="6973226350963971018">"Безжично отстранување грешки"</string> - <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Режим на отстранување грешки кога е поврзано Wi‑Fi"</string> + <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Режим за отстранување грешки кога е поврзано Wi‑Fi"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Грешка"</string> <string name="adb_wireless_settings" msgid="2295017847215680229">"Безжично отстранување грешки"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"За да ги гледате и користите достапните уреди, вклучете го безжичното отстранување грешки"</string> diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index e3f75e3e0b34..06a97b17a73c 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -711,10 +711,9 @@ <service android:name=".controls.controller.AuxiliaryPersistenceWrapper$DeletionJobService" android:permission="android.permission.BIND_JOB_SERVICE"/> - <!-- started from ControlsFavoritingActivity --> + <!-- started from ControlsRequestReceiver --> <activity android:name=".controls.management.ControlsRequestDialog" - android:exported="true" android:theme="@style/Theme.ControlsRequestDialog" android:finishOnCloseSystemDialogs="true" android:showForAllUsers="true" diff --git a/packages/SystemUI/docs/camera.md b/packages/SystemUI/docs/camera.md new file mode 100644 index 000000000000..7a7a5aa3eb7f --- /dev/null +++ b/packages/SystemUI/docs/camera.md @@ -0,0 +1,33 @@ +# How double-click power launches the camera + +_as of august 2020_ + + +## Sequence of events + + + +1. [PhoneWindowManager.java](/services/core/java/com/android/server/policy/PhoneWindowManager.java) is responsible for all power button presses (see `interceptPowerKeyDown`). +2. Even though PWMgr has a lot of logic to detect all manner of power button multipresses and gestures, it also checks with GestureLauncherService, which is also [offered the chance](/services/core/java/com/android/server/policy/PhoneWindowManager.java#943) to [intercept](/services/core/java/com/android/server/GestureLauncherService.java#358) the power key. +3. GLS is responsible for the camera timeout, and if it detects one, it [forwards it to the StatusBarManagerService](/services/core/java/com/android/server/GestureLauncherService.java#475) (which hands it off to SystemUI). +4. Inside SystemUI, [onCameraLaunchDetected](/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java#3927) looks at the keyguard state and determines + 1. whether the camera is even allowed + 2. whether the screen is on; if not, we need to delay until that happens + 3. whether the device is locked (defined as "keyuguard is showing"). +5. If the device is unlocked (no keyguard), the camera is launched immediately. [Callsite](/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java#3949). +6. If the keyguard is up, however, [KeyguardBottomAreaView.launchCamera](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#477) takes over to handle the "secure camera" (a different intent, usually directing to the same app, but giving that app the cue to not allow access to the photo roll, etc). +7. If the intent [would have to launch a resolver](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#480) (the user has multiple cameras installed and hasn’t chosen one to always launch for the `SECURE_CAMERA_INTENT`), + 1. In order to show the resolver, the lockscreen "bouncer" (authentication method) [is first presented](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#523). +8. Otherwise (just one secure camera), [it is launched](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#501) (with some window animation gymnastics). + + +## Which intent launches? + + + +* If the keyguard is not showing (device is unlocked) + * `KeyguardBottomAreaView.INSECURE_CAMERA_INTENT`, defined to be `MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA`. + * [Callsite](/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java#3950) in StatusBar.java. +* If the keyguard is showing (device locked) + * [KeyguardBottomAreaView.getCameraIntent()](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#366) is consulted, which allows the "keyguard right button" (which we don’t actually show) to control the camera intent. The [default implementation](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#831) returns one of `KeyguardBottomAreaView.INSECURE_CAMERA_INTENT` or `KeyguardBottomAreaView.SECURE_CAMERA_INTENT`, which are `MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA` and `MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE`, respectively. + * [Callsite](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#523) in KeyguardBottomAreaView.java. diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt index b9b849b8488e..83de3243602b 100644 --- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt +++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt @@ -16,7 +16,6 @@ package com.android.systemui.broadcast -import android.app.ActivityManager import android.content.BroadcastReceiver import android.content.Context import android.content.Intent @@ -33,6 +32,7 @@ import com.android.internal.util.IndentingPrintWriter import com.android.systemui.Dumpable import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger import com.android.systemui.dump.DumpManager +import com.android.systemui.settings.UserTracker import java.io.FileDescriptor import java.io.PrintWriter import java.util.concurrent.Executor @@ -47,8 +47,6 @@ data class ReceiverData( private const val MSG_ADD_RECEIVER = 0 private const val MSG_REMOVE_RECEIVER = 1 private const val MSG_REMOVE_RECEIVER_FOR_USER = 2 -private const val MSG_USER_SWITCH = 3 -private const val MSG_SET_STARTING_USER = 99 private const val TAG = "BroadcastDispatcher" private const val DEBUG = true @@ -68,23 +66,15 @@ open class BroadcastDispatcher constructor ( private val bgLooper: Looper, private val bgExecutor: Executor, private val dumpManager: DumpManager, - private val logger: BroadcastDispatcherLogger -) : Dumpable, BroadcastReceiver() { + private val logger: BroadcastDispatcherLogger, + private val userTracker: UserTracker +) : Dumpable { // Only modify in BG thread private val receiversByUser = SparseArray<UserBroadcastDispatcher>(20) fun initialize() { dumpManager.registerDumpable(javaClass.name, this) - handler.sendEmptyMessage(MSG_SET_STARTING_USER) - registerReceiver(this, IntentFilter(Intent.ACTION_USER_SWITCHED), null, UserHandle.ALL) - } - - override fun onReceive(context: Context, intent: Intent) { - if (intent.action == Intent.ACTION_USER_SWITCHED) { - val user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL) - handler.obtainMessage(MSG_USER_SWITCH, user, 0).sendToTarget() - } } /** @@ -181,7 +171,6 @@ open class BroadcastDispatcher constructor ( pw.println("Broadcast dispatcher:") val ipw = IndentingPrintWriter(pw, " ") ipw.increaseIndent() - ipw.println("Current user: ${handler.currentUser}") for (index in 0 until receiversByUser.size()) { ipw.println("User ${receiversByUser.keyAt(index)}") receiversByUser.valueAt(index).dump(fd, ipw, args) @@ -190,7 +179,6 @@ open class BroadcastDispatcher constructor ( } private val handler = object : Handler(bgLooper) { - var currentUser = UserHandle.USER_SYSTEM override fun handleMessage(msg: Message) { when (msg.what) { @@ -199,7 +187,7 @@ open class BroadcastDispatcher constructor ( // If the receiver asked to be registered under the current user, we register // under the actual current user. val userId = if (data.user.identifier == UserHandle.USER_CURRENT) { - currentUser + userTracker.userId } else { data.user.identifier } @@ -221,14 +209,6 @@ open class BroadcastDispatcher constructor ( MSG_REMOVE_RECEIVER_FOR_USER -> { receiversByUser.get(msg.arg1)?.unregisterReceiver(msg.obj as BroadcastReceiver) } - - MSG_USER_SWITCH -> { - currentUser = msg.arg1 - } - MSG_SET_STARTING_USER -> { - currentUser = ActivityManager.getCurrentUser() - } - else -> super.handleMessage(msg) } } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java index ac01ba1539b3..38e12a6ed5f8 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java @@ -61,6 +61,7 @@ import com.android.systemui.plugins.PluginInitializerImpl; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.recents.Recents; +import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.shared.plugins.PluginManagerImpl; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -269,10 +270,11 @@ public class DependencyProvider { @Background Looper backgroundLooper, @Background Executor backgroundExecutor, DumpManager dumpManager, - BroadcastDispatcherLogger logger + BroadcastDispatcherLogger logger, + UserTracker userTracker ) { BroadcastDispatcher bD = new BroadcastDispatcher(context, backgroundLooper, - backgroundExecutor, dumpManager, logger); + backgroundExecutor, dumpManager, logger, userTracker); bD.initialize(); return bD; } diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java index 862405609de8..5793cddd7d26 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java @@ -57,7 +57,6 @@ import android.window.TaskOrganizer; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import android.window.WindowContainerTransactionCallback; -import android.window.WindowOrganizer; import com.android.internal.os.SomeArgs; import com.android.systemui.dagger.SysUISingleton; @@ -309,7 +308,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize // Don't bother doing an animation if the display rotation differs or if it's in // a non-supported windowing mode applyWindowingModeChangeOnExit(wct, direction); - WindowOrganizer.applyTransaction(wct); + mTaskOrganizer.applyTransaction(wct); // Send finished callback though animation is ignored. sendOnPipTransitionFinished(direction); mInPip = false; @@ -379,7 +378,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize // Reset the task bounds first to ensure the activity configuration is reset as well final WindowContainerTransaction wct = new WindowContainerTransaction(); wct.setBounds(mToken, null); - WindowOrganizer.applyTransaction(wct); + mTaskOrganizer.applyTransaction(wct); ActivityTaskManager.getService().removeStacksInWindowingModes( new int[]{ WINDOWING_MODE_PINNED }); @@ -932,7 +931,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize */ public void applyFinishBoundsResize(@NonNull WindowContainerTransaction wct, @PipAnimationController.TransitionDirection int direction) { - WindowOrganizer.applyTransaction(wct); + mTaskOrganizer.applyTransaction(wct); } /** diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java index b7175eabab39..0fe381746449 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java +++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java @@ -39,6 +39,7 @@ import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager; @@ -78,7 +79,7 @@ public abstract class SysuiTestCase { Dependency.setInstance(mDependency); mFakeBroadcastDispatcher = new FakeBroadcastDispatcher(mContext, mock(Looper.class), mock(Executor.class), mock(DumpManager.class), - mock(BroadcastDispatcherLogger.class)); + mock(BroadcastDispatcherLogger.class), mock(UserTracker.class)); mRealInstrumentation = InstrumentationRegistry.getInstrumentation(); Instrumentation inst = spy(mRealInstrumentation); diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt index 22e9594ca420..65301fe6fd3e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.broadcast import android.content.BroadcastReceiver import android.content.Context -import android.content.Intent import android.content.IntentFilter import android.os.Handler import android.os.Looper @@ -30,6 +29,7 @@ import android.testing.TestableLooper import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger import com.android.systemui.dump.DumpManager +import com.android.systemui.settings.UserTracker import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.time.FakeSystemClock import junit.framework.Assert.assertSame @@ -80,6 +80,8 @@ class BroadcastDispatcherTest : SysuiTestCase() { private lateinit var mockHandler: Handler @Mock private lateinit var logger: BroadcastDispatcherLogger + @Mock + private lateinit var userTracker: UserTracker private lateinit var executor: Executor @@ -101,6 +103,7 @@ class BroadcastDispatcherTest : SysuiTestCase() { mock(Executor::class.java), mock(DumpManager::class.java), logger, + userTracker, mapOf(0 to mockUBRUser0, 1 to mockUBRUser1)) // These should be valid filters @@ -178,11 +181,7 @@ class BroadcastDispatcherTest : SysuiTestCase() { @Test fun testRegisterCurrentAsActualUser() { - val intent = Intent(Intent.ACTION_USER_SWITCHED).apply { - putExtra(Intent.EXTRA_USER_HANDLE, user1.identifier) - } - broadcastDispatcher.onReceive(mockContext, intent) - testableLooper.processAllMessages() + `when`(userTracker.userId).thenReturn(user1.identifier) broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter, mockHandler, UserHandle.CURRENT) @@ -250,8 +249,9 @@ class BroadcastDispatcherTest : SysuiTestCase() { executor: Executor, dumpManager: DumpManager, logger: BroadcastDispatcherLogger, + userTracker: UserTracker, var mockUBRMap: Map<Int, UserBroadcastDispatcher> - ) : BroadcastDispatcher(context, bgLooper, executor, dumpManager, logger) { + ) : BroadcastDispatcher(context, bgLooper, executor, dumpManager, logger, userTracker) { override fun createUBRForUser(userId: Int): UserBroadcastDispatcher { return mockUBRMap.getOrDefault(userId, mock(UserBroadcastDispatcher::class.java)) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt index 949932da4d50..da00e7e9518b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt @@ -26,6 +26,7 @@ import android.util.Log import com.android.systemui.SysuiTestableContext import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger import com.android.systemui.dump.DumpManager +import com.android.systemui.settings.UserTracker import java.util.concurrent.Executor class FakeBroadcastDispatcher( @@ -33,8 +34,9 @@ class FakeBroadcastDispatcher( looper: Looper, executor: Executor, dumpManager: DumpManager, - logger: BroadcastDispatcherLogger -) : BroadcastDispatcher(context, looper, executor, dumpManager, logger) { + logger: BroadcastDispatcherLogger, + userTracker: UserTracker +) : BroadcastDispatcher(context, looper, executor, dumpManager, logger, userTracker) { private val registeredReceivers = ArraySet<BroadcastReceiver>() diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index f372c6f85ec6..0d79240a4b59 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -166,6 +166,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private String mAddress; private String mName; private final ContentResolver mContentResolver; + private final int mUserId; private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks; private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks; private IBinder mBluetoothBinder; @@ -481,6 +482,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mName = null; mErrorRecoveryRetryCounter = 0; mContentResolver = context.getContentResolver(); + mUserId = mContentResolver.getUserId(); // Observe BLE scan only mode settings change. registerForBleScanModeChange(); mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>(); @@ -625,7 +627,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } if (mContext.getResources() .getBoolean(com.android.internal.R.bool.config_bluetooth_address_validation) - && Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) + && Settings.Secure.getIntForUser(mContentResolver, + SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0, mUserId) == 0) { // if the valid flag is not set, don't load the address and name if (DBG) { @@ -633,8 +636,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } return; } - mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME); - mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS); + mName = Settings.Secure.getStringForUser( + mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, mUserId); + mAddress = Settings.Secure.getStringForUser( + mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, mUserId); if (DBG) { Slog.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress); } @@ -648,26 +653,31 @@ class BluetoothManagerService extends IBluetoothManager.Stub { */ private void storeNameAndAddress(String name, String address) { if (name != null) { - Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name); + Settings.Secure.putStringForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name, + mUserId); mName = name; if (DBG) { - Slog.d(TAG, "Stored Bluetooth name: " + Settings.Secure.getString(mContentResolver, - SECURE_SETTINGS_BLUETOOTH_NAME)); + Slog.d(TAG, "Stored Bluetooth name: " + Settings.Secure.getStringForUser( + mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, + mUserId)); } } if (address != null) { - Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address); + Settings.Secure.putStringForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, + address, mUserId); mAddress = address; if (DBG) { Slog.d(TAG, - "Stored Bluetoothaddress: " + Settings.Secure.getString(mContentResolver, - SECURE_SETTINGS_BLUETOOTH_ADDRESS)); + "Stored Bluetoothaddress: " + Settings.Secure.getStringForUser( + mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, + mUserId)); } } if ((name != null) && (address != null)) { - Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1); + Settings.Secure.putIntForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1, + mUserId); } } diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 1615998f7787..5447605a36d1 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -28,7 +28,6 @@ import android.media.AudioDeviceAttributes; import android.media.AudioRoutesInfo; import android.media.AudioSystem; import android.media.IAudioRoutesObserver; -import android.media.ICapturePresetDevicesRoleDispatcher; import android.media.IStrategyPreferredDevicesDispatcher; import android.media.MediaMetrics; import android.os.Binder; @@ -547,25 +546,6 @@ import java.util.concurrent.atomic.AtomicBoolean; mDeviceInventory.unregisterStrategyPreferredDevicesDispatcher(dispatcher); } - /*package*/ int setPreferredDevicesForCapturePresetSync(int capturePreset, - @NonNull List<AudioDeviceAttributes> devices) { - return mDeviceInventory.setPreferredDevicesForCapturePresetSync(capturePreset, devices); - } - - /*package*/ int clearPreferredDevicesForCapturePresetSync(int capturePreset) { - return mDeviceInventory.clearPreferredDevicesForCapturePresetSync(capturePreset); - } - - /*package*/ void registerCapturePresetDevicesRoleDispatcher( - @NonNull ICapturePresetDevicesRoleDispatcher dispatcher) { - mDeviceInventory.registerCapturePresetDevicesRoleDispatcher(dispatcher); - } - - /*package*/ void unregisterCapturePresetDevicesRoleDispatcher( - @NonNull ICapturePresetDevicesRoleDispatcher dispatcher) { - mDeviceInventory.unregisterCapturePresetDevicesRoleDispatcher(dispatcher); - } - //--------------------------------------------------------------------- // Communication with (to) AudioService //TODO check whether the AudioService methods are candidates to move here @@ -714,17 +694,6 @@ import java.util.concurrent.atomic.AtomicBoolean; sendIMsgNoDelay(MSG_I_SAVE_REMOVE_PREF_DEVICES_FOR_STRATEGY, SENDMSG_QUEUE, strategy); } - /*package*/ void postSaveSetPreferredDevicesForCapturePreset( - int capturePreset, List<AudioDeviceAttributes> devices) { - sendILMsgNoDelay( - MSG_IL_SAVE_PREF_DEVICES_FOR_CAPTURE_PRESET, SENDMSG_QUEUE, capturePreset, devices); - } - - /*package*/ void postSaveClearPreferredDevicesForCapturePreset(int capturePreset) { - sendIMsgNoDelay( - MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET, SENDMSG_QUEUE, capturePreset); - } - //--------------------------------------------------------------------- // Method forwarding between the helper classes (BtHelper, AudioDeviceInventory) // only call from a "handle"* method or "on"* method @@ -1129,17 +1098,6 @@ import java.util.concurrent.atomic.AtomicBoolean; case MSG_CHECK_MUTE_MUSIC: checkMessagesMuteMusic(0); break; - case MSG_IL_SAVE_PREF_DEVICES_FOR_CAPTURE_PRESET: { - final int capturePreset = msg.arg1; - final List<AudioDeviceAttributes> devices = - (List<AudioDeviceAttributes>) msg.obj; - mDeviceInventory.onSaveSetPreferredDevicesForCapturePreset( - capturePreset, devices); - } break; - case MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET: { - final int capturePreset = msg.arg1; - mDeviceInventory.onSaveClearPreferredDevicesForCapturePreset(capturePreset); - } break; default: Log.wtf(TAG, "Invalid message " + msg.what); } @@ -1216,9 +1174,6 @@ import java.util.concurrent.atomic.AtomicBoolean; private static final int MSG_CHECK_MUTE_MUSIC = 36; private static final int MSG_REPORT_NEW_ROUTES_A2DP = 37; - private static final int MSG_IL_SAVE_PREF_DEVICES_FOR_CAPTURE_PRESET = 38; - private static final int MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET = 39; - private static boolean isMessageHandledUnderWakelock(int msgId) { switch(msgId) { diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 33a8a30243de..fbf07cc591ff 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -31,7 +31,6 @@ import android.media.AudioPort; import android.media.AudioRoutesInfo; import android.media.AudioSystem; import android.media.IAudioRoutesObserver; -import android.media.ICapturePresetDevicesRoleDispatcher; import android.media.IStrategyPreferredDevicesDispatcher; import android.media.MediaMetrics; import android.os.Binder; @@ -141,10 +140,6 @@ public class AudioDeviceInventory { private final ArrayMap<Integer, List<AudioDeviceAttributes>> mPreferredDevices = new ArrayMap<>(); - // List of preferred devices of capture preset - private final ArrayMap<Integer, List<AudioDeviceAttributes>> mPreferredDevicesForCapturePreset = - new ArrayMap<>(); - // the wrapper for AudioSystem static methods, allows us to spy AudioSystem private final @NonNull AudioSystemAdapter mAudioSystem; @@ -159,10 +154,6 @@ public class AudioDeviceInventory { final RemoteCallbackList<IStrategyPreferredDevicesDispatcher> mPrefDevDispatchers = new RemoteCallbackList<IStrategyPreferredDevicesDispatcher>(); - // Monitoring of devices for role and capture preset - final RemoteCallbackList<ICapturePresetDevicesRoleDispatcher> mDevRoleCapturePresetDispatchers = - new RemoteCallbackList<ICapturePresetDevicesRoleDispatcher>(); - /*package*/ AudioDeviceInventory(@NonNull AudioDeviceBroker broker) { mDeviceBroker = broker; mAudioSystem = AudioSystemAdapter.getDefaultAdapter(); @@ -252,9 +243,6 @@ public class AudioDeviceInventory { pw.println(" " + prefix + " type:0x" + Integer.toHexString(keyType) + " (" + AudioSystem.getDeviceName(keyType) + ") addr:" + valueAddress); }); - mPreferredDevicesForCapturePreset.forEach((capturePreset, devices) -> { - pw.println(" " + prefix + "capturePreset:" + capturePreset - + " devices:" + devices); }); } //------------------------------------------------------------ @@ -282,9 +270,6 @@ public class AudioDeviceInventory { mAudioSystem.setDevicesRoleForStrategy( strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices); }); } - synchronized (mPreferredDevicesForCapturePreset) { - // TODO: call audiosystem to restore - } } // only public for mocking/spying @@ -628,20 +613,6 @@ public class AudioDeviceInventory { dispatchPreferredDevice(strategy, new ArrayList<AudioDeviceAttributes>()); } - /*package*/ void onSaveSetPreferredDevicesForCapturePreset( - int capturePreset, @NonNull List<AudioDeviceAttributes> devices) { - mPreferredDevicesForCapturePreset.put(capturePreset, devices); - dispatchDevicesRoleForCapturePreset( - capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED, devices); - } - - /*package*/ void onSaveClearPreferredDevicesForCapturePreset(int capturePreset) { - mPreferredDevicesForCapturePreset.remove(capturePreset); - dispatchDevicesRoleForCapturePreset( - capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED, - new ArrayList<AudioDeviceAttributes>()); - } - //------------------------------------------------------------ // @@ -680,41 +651,6 @@ public class AudioDeviceInventory { mPrefDevDispatchers.unregister(dispatcher); } - /*package*/ int setPreferredDevicesForCapturePresetSync( - int capturePreset, @NonNull List<AudioDeviceAttributes> devices) { - final long identity = Binder.clearCallingIdentity(); - final int status = mAudioSystem.setDevicesRoleForCapturePreset( - capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED, devices); - Binder.restoreCallingIdentity(identity); - - if (status == AudioSystem.SUCCESS) { - mDeviceBroker.postSaveSetPreferredDevicesForCapturePreset(capturePreset, devices); - } - return status; - } - - /*package*/ int clearPreferredDevicesForCapturePresetSync(int capturePreset) { - final long identity = Binder.clearCallingIdentity(); - final int status = mAudioSystem.clearDevicesRoleForCapturePreset( - capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED); - Binder.restoreCallingIdentity(identity); - - if (status == AudioSystem.SUCCESS) { - mDeviceBroker.postSaveClearPreferredDevicesForCapturePreset(capturePreset); - } - return status; - } - - /*package*/ void registerCapturePresetDevicesRoleDispatcher( - @NonNull ICapturePresetDevicesRoleDispatcher dispatcher) { - mDevRoleCapturePresetDispatchers.register(dispatcher); - } - - /*package*/ void unregisterCapturePresetDevicesRoleDispatcher( - @NonNull ICapturePresetDevicesRoleDispatcher dispatcher) { - mDevRoleCapturePresetDispatchers.unregister(dispatcher); - } - /** * Implements the communication with AudioSystem to (dis)connect a device in the native layers * @param connect true if connection @@ -1370,19 +1306,6 @@ public class AudioDeviceInventory { mPrefDevDispatchers.finishBroadcast(); } - private void dispatchDevicesRoleForCapturePreset( - int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devices) { - final int nbDispatchers = mDevRoleCapturePresetDispatchers.beginBroadcast(); - for (int i = 0; i < nbDispatchers; ++i) { - try { - mDevRoleCapturePresetDispatchers.getBroadcastItem(i).dispatchDevicesRoleChanged( - capturePreset, role, devices); - } catch (RemoteException e) { - } - } - mDevRoleCapturePresetDispatchers.finishBroadcast(); - } - //---------------------------------------------------------- // For tests only diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 5f6491093453..4378490d19c5 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -84,7 +84,6 @@ import android.media.IAudioFocusDispatcher; import android.media.IAudioRoutesObserver; import android.media.IAudioServerStateDispatcher; import android.media.IAudioService; -import android.media.ICapturePresetDevicesRoleDispatcher; import android.media.IPlaybackConfigDispatcher; import android.media.IRecordingConfigDispatcher; import android.media.IRingtonePlayer; @@ -1988,94 +1987,6 @@ public class AudioService extends IAudioService.Stub mDeviceBroker.unregisterStrategyPreferredDevicesDispatcher(dispatcher); } - /** - * @see AudioManager#setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes) - */ - public int setPreferredDevicesForCapturePreset( - int capturePreset, List<AudioDeviceAttributes> devices) { - if (devices == null) { - return AudioSystem.ERROR; - } - enforceModifyAudioRoutingPermission(); - final String logString = String.format( - "setPreferredDevicesForCapturePreset u/pid:%d/%d source:%d dev:%s", - Binder.getCallingUid(), Binder.getCallingPid(), capturePreset, - devices.stream().map(e -> e.toString()).collect(Collectors.joining(","))); - sDeviceLogger.log(new AudioEventLogger.StringEvent(logString).printLog(TAG)); - if (devices.stream().anyMatch(device -> - device.getRole() == AudioDeviceAttributes.ROLE_OUTPUT)) { - Log.e(TAG, "Unsupported output routing in " + logString); - return AudioSystem.ERROR; - } - - final int status = mDeviceBroker.setPreferredDevicesForCapturePresetSync( - capturePreset, devices); - if (status != AudioSystem.SUCCESS) { - Log.e(TAG, String.format("Error %d in %s)", status, logString)); - } - - return status; - } - - /** @see AudioManager#clearPreferredDevicesForCapturePreset(int) */ - public int clearPreferredDevicesForCapturePreset(int capturePreset) { - enforceModifyAudioRoutingPermission(); - final String logString = String.format( - "removePreferredDeviceForCapturePreset source:%d", capturePreset); - sDeviceLogger.log(new AudioEventLogger.StringEvent(logString).printLog(TAG)); - - final int status = mDeviceBroker.clearPreferredDevicesForCapturePresetSync(capturePreset); - if (status != AudioSystem.SUCCESS) { - Log.e(TAG, String.format("Error %d in %s", status, logString)); - } - return status; - } - - /** - * @see AudioManager#getPreferredDevicesForCapturePreset(int) - */ - public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(int capturePreset) { - enforceModifyAudioRoutingPermission(); - List<AudioDeviceAttributes> devices = new ArrayList<>(); - final long identity = Binder.clearCallingIdentity(); - final int status = AudioSystem.getDevicesForRoleAndCapturePreset( - capturePreset, AudioSystem.DEVICE_ROLE_PREFERRED, devices); - Binder.restoreCallingIdentity(identity); - if (status != AudioSystem.SUCCESS) { - Log.e(TAG, String.format("Error %d in getPreferredDeviceForCapturePreset(%d)", - status, capturePreset)); - return new ArrayList<AudioDeviceAttributes>(); - } else { - return devices; - } - } - - /** - * @see AudioManager#addOnPreferredDevicesForCapturePresetChangedListener( - * Executor, OnPreferredDevicesForCapturePresetChangedListener) - */ - public void registerCapturePresetDevicesRoleDispatcher( - @Nullable ICapturePresetDevicesRoleDispatcher dispatcher) { - if (dispatcher == null) { - return; - } - enforceModifyAudioRoutingPermission(); - mDeviceBroker.registerCapturePresetDevicesRoleDispatcher(dispatcher); - } - - /** - * @see AudioManager#removeOnPreferredDevicesForCapturePresetChangedListener( - * AudioManager.OnPreferredDevicesForCapturePresetChangedListener) - */ - public void unregisterCapturePresetDevicesRoleDispatcher( - @Nullable ICapturePresetDevicesRoleDispatcher dispatcher) { - if (dispatcher == null) { - return; - } - enforceModifyAudioRoutingPermission(); - mDeviceBroker.unregisterCapturePresetDevicesRoleDispatcher(dispatcher); - } - /** @see AudioManager#getDevicesForAttributes(AudioAttributes) */ public @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributes( @NonNull AudioAttributes attributes) { diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java index ae64990fd8d0..a0e1ca78a5e7 100644 --- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java +++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java @@ -101,40 +101,6 @@ public class AudioSystemAdapter { } /** - * Same as (@link AudioSystem#setDevicesRoleForCapturePreset(int, List)) - * @param capturePreset - * @param role - * @param devices - * @return - */ - public int setDevicesRoleForCapturePreset(int capturePreset, int role, - @NonNull List<AudioDeviceAttributes> devices) { - return AudioSystem.setDevicesRoleForCapturePreset(capturePreset, role, devices); - } - - /** - * Same as {@link AudioSystem#removeDevicesRoleForCapturePreset(int, int)} - * @param capturePreset - * @param role - * @param devicesToRemove - * @return - */ - public int removeDevicesRoleForCapturePreset( - int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devicesToRemove) { - return AudioSystem.removeDevicesRoleForCapturePreset(capturePreset, role, devicesToRemove); - } - - /** - * Same as {@link AudioSystem#} - * @param capturePreset - * @param role - * @return - */ - public int clearDevicesRoleForCapturePreset(int capturePreset, int role) { - return AudioSystem.clearDevicesRoleForCapturePreset(capturePreset, role); - } - - /** * Same as {@link AudioSystem#setParameters(String)} * @param keyValuePairs * @return diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index a0bc7d8954fb..5d2f51230c12 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -57,10 +57,12 @@ import android.text.TextUtils; import android.util.Slog; import android.util.SparseArray; import android.view.autofill.AutofillManagerInternal; +import android.widget.Toast; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.SystemService.TargetUser; +import com.android.server.UiThread; import com.android.server.contentcapture.ContentCaptureManagerInternal; import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.wm.WindowManagerInternal; @@ -391,7 +393,9 @@ public class ClipboardService extends SystemService { return null; } addActiveOwnerLocked(intendingUid, pkg); - return getClipboard(intendingUserId).primaryClip; + PerUserClipboard clipboard = getClipboard(intendingUserId); + maybeNotify(pkg, intendingUid, intendingUserId, clipboard); + return clipboard.primaryClip; } } @@ -821,4 +825,65 @@ public class ClipboardService extends SystemService { return appOpsResult == AppOpsManager.MODE_ALLOWED; } + + /** + * Potentially notifies the user (via a toast) about an app accessing the clipboard. + * TODO(b/167676460): STOPSHIP as we don't want this code as-is to launch. Just an experiment. + */ + private void maybeNotify(String callingPackage, int uid, @UserIdInt int userId, + PerUserClipboard clipboard) { + if (clipboard.primaryClip == null) { + return; + } + if (Settings.Global.getInt(getContext().getContentResolver(), + "clipboard_access_toast_enabled", 0) == 0) { + return; + } + // Don't notify if the app accessing the clipboard is the same as the current owner. + if (UserHandle.isSameApp(uid, clipboard.primaryClipUid)) { + return; + } + // Exclude some special cases. It's a bit wasteful to check these again here, but for now + // beneficial to have all the logic contained in this single (probably temporary) method. + String defaultIme = Settings.Secure.getStringForUser(getContext().getContentResolver(), + Settings.Secure.DEFAULT_INPUT_METHOD, userId); + if (!TextUtils.isEmpty(defaultIme)) { + final String imePkg = ComponentName.unflattenFromString(defaultIme).getPackageName(); + if (imePkg.equals(callingPackage)) { + return; + } + } + if (mContentCaptureInternal != null + && mContentCaptureInternal.isContentCaptureServiceForUser(uid, userId)) { + return; + } + if (mAutofillInternal != null + && mAutofillInternal.isAugmentedAutofillServiceForUser(uid, userId)) { + return; + } + // Load the labels for the calling app and the app that set the clipboard content. + final long ident = Binder.clearCallingIdentity(); + try { + final IPackageManager pm = AppGlobals.getPackageManager(); + String message; + final CharSequence callingLabel = mPm.getApplicationLabel( + pm.getApplicationInfo(callingPackage, 0, userId)); + final String[] packagesForUid = pm.getPackagesForUid(clipboard.primaryClipUid); + if (packagesForUid != null && packagesForUid.length > 0) { + final CharSequence clipLabel = mPm.getApplicationLabel( + pm.getApplicationInfo(packagesForUid[0], 0, + UserHandle.getUserId(clipboard.primaryClipUid))); + message = callingLabel + " pasted from " + clipLabel; + } else { + message = callingLabel + " pasted from clipboard"; + } + Slog.i(TAG, message); + Toast.makeText(getContext(), UiThread.get().getLooper(), message, Toast.LENGTH_SHORT) + .show(); + } catch (RemoteException e) { + /* ignore */ + } finally { + Binder.restoreCallingIdentity(ident); + } + } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java index 7b52ddef29bc..7dc4d6e8efcf 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecController.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java @@ -893,7 +893,7 @@ final class HdmiCecController { @Override public void serviceDied(long cookie) { if (cookie == HDMI_CEC_HAL_DEATH_COOKIE) { - HdmiLogger.error(TAG, "Service died cokkie : " + cookie + "; reconnecting"); + HdmiLogger.error("Service died cookie : " + cookie + "; reconnecting"); connectToHal(); } } 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 3e5b6e3f462f..a4486d7b5898 100644 --- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java @@ -85,7 +85,9 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * A GNSS implementation of LocationProvider used by LocationManager. @@ -181,7 +183,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private static final int INJECT_NTP_TIME = 5; // PSDS stands for Predicted Satellite Data Service private static final int DOWNLOAD_PSDS_DATA = 6; - private static final int DOWNLOAD_PSDS_DATA_FINISHED = 11; private static final int INITIALIZE_HANDLER = 13; private static final int REQUEST_LOCATION = 16; private static final int REPORT_LOCATION = 17; // HAL reports location @@ -288,6 +289,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private static final long DOWNLOAD_PSDS_DATA_TIMEOUT_MS = 60 * 1000; private static final long WAKELOCK_TIMEOUT_MILLIS = 30 * 1000; + @GuardedBy("mLock") private final ExponentialBackOff mPsdsBackOff = new ExponentialBackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL); @@ -297,14 +299,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private boolean mShutdown; - // states for injecting ntp and downloading psds data - private static final int STATE_PENDING_NETWORK = 0; - private static final int STATE_DOWNLOADING = 1; - private static final int STATE_IDLE = 2; - - // flags to trigger NTP or PSDS data download when network becomes available - // initialized to true so we do NTP and PSDS when the network comes up after booting - private int mDownloadPsdsDataPending = STATE_PENDING_NETWORK; + @GuardedBy("mLock") + private Set<Integer> mPendingDownloadPsdsTypes = new HashSet<>(); // true if GPS is navigating private boolean mNavigating; @@ -610,6 +606,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mNIHandler = new GpsNetInitiatedHandler(context, mNetInitiatedListener, mSuplEsEnabled); + // Trigger PSDS data download when the network comes up after booting. + mPendingDownloadPsdsTypes.add(GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX); mNetworkConnectivityHandler = new GnssNetworkConnectivityHandler(context, GnssLocationProvider.this::onNetworkAvailable, mLooper, mNIHandler); @@ -670,10 +668,13 @@ public class GnssLocationProvider extends AbstractLocationProvider implements */ private void onNetworkAvailable() { mNtpTimeHelper.onNetworkAvailable(); - if (mDownloadPsdsDataPending == STATE_PENDING_NETWORK) { - if (mSupportsPsds) { - // Download only if supported, (prevents an unnecessary on-boot download) - psdsDownloadRequest(/* psdsType= */ GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX); + // Download only if supported, (prevents an unnecessary on-boot download) + if (mSupportsPsds) { + synchronized (mLock) { + for (int psdsType : mPendingDownloadPsdsTypes) { + downloadPsdsData(psdsType); + } + mPendingDownloadPsdsTypes.clear(); } } } @@ -799,17 +800,13 @@ public class GnssLocationProvider extends AbstractLocationProvider implements Log.d(TAG, "handleDownloadPsdsData() called when PSDS not supported"); return; } - if (mDownloadPsdsDataPending == STATE_DOWNLOADING) { - // already downloading data - return; - } if (!mNetworkConnectivityHandler.isDataNetworkConnected()) { // try again when network is up - mDownloadPsdsDataPending = STATE_PENDING_NETWORK; + synchronized (mLock) { + mPendingDownloadPsdsTypes.add(psdsType); + } return; } - mDownloadPsdsDataPending = STATE_DOWNLOADING; - synchronized (mLock) { // hold wake lock while task runs mDownloadPsdsWakeLock.acquire(DOWNLOAD_PSDS_DATA_TIMEOUT_MS); @@ -820,20 +817,24 @@ public class GnssLocationProvider extends AbstractLocationProvider implements mGnssConfiguration.getProperties()); 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, psdsType); - mPsdsBackOff.reset(); - } - - sendMessage(DOWNLOAD_PSDS_DATA_FINISHED, 0, null); - - if (data == null) { - // try again later - // since this is delayed and not urgent we do not hold a wake lock here - // the arg2 below should not be 1 otherwise the wakelock will be under-locked. + mHandler.post(() -> { + if (DEBUG) Log.d(TAG, "calling native_inject_psds_data"); + native_inject_psds_data(data, data.length, psdsType); + synchronized (mLock) { + mPsdsBackOff.reset(); + } + }); + } else { + // Try download PSDS data again later according to backoff time. + // Since this is delayed and not urgent, we do not hold a wake lock here. + // The arg2 below should not be 1 otherwise the wakelock will be under-locked. + long backoffMillis; + synchronized (mLock) { + backoffMillis = mPsdsBackOff.nextBackoffMillis(); + } mHandler.sendMessageDelayed( mHandler.obtainMessage(DOWNLOAD_PSDS_DATA, psdsType, 0, null), - mPsdsBackOff.nextBackoffMillis()); + backoffMillis); } // Release wake lock held by task, synchronize on mLock in case multiple @@ -1128,7 +1129,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements requestUtcTime(); } else if ("force_psds_injection".equals(command)) { if (mSupportsPsds) { - psdsDownloadRequest(/* psdsType= */ + downloadPsdsData(/* psdsType= */ GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX); } } else { @@ -1581,8 +1582,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements reportLocation(locations); } - void psdsDownloadRequest(int psdsType) { - if (DEBUG) Log.d(TAG, "psdsDownloadRequest. psdsType: " + psdsType); + void downloadPsdsData(int psdsType) { + if (DEBUG) Log.d(TAG, "downloadPsdsData. psdsType: " + psdsType); sendMessage(DOWNLOAD_PSDS_DATA, psdsType, null); } @@ -1896,9 +1897,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements case DOWNLOAD_PSDS_DATA: handleDownloadPsdsData(msg.arg1); break; - case DOWNLOAD_PSDS_DATA_FINISHED: - mDownloadPsdsDataPending = STATE_IDLE; - break; case INITIALIZE_HANDLER: handleInitialize(); break; @@ -2007,8 +2005,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements return "REQUEST_LOCATION"; case DOWNLOAD_PSDS_DATA: return "DOWNLOAD_PSDS_DATA"; - case DOWNLOAD_PSDS_DATA_FINISHED: - return "DOWNLOAD_PSDS_DATA_FINISHED"; case INITIALIZE_HANDLER: return "INITIALIZE_HANDLER"; case REPORT_LOCATION: diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java index 8e81f29550d6..2bf6af25422a 100644 --- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java +++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java @@ -519,7 +519,7 @@ public class GnssManagerService implements GnssNative.Callbacks { @Override public void psdsDownloadRequest(int psdsType) { - mGnssLocationProvider.psdsDownloadRequest(psdsType); + mGnssLocationProvider.downloadPsdsData(psdsType); } @Override diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 162bfee8848d..155af82289d4 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -656,7 +656,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements throw new IllegalArgumentException("Invalid install mode: " + params.mode); } - // If caller requested explicit location, sanity check it, otherwise + // If caller requested explicit location, validity check it, otherwise // resolve the best internal or adopted location. if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) { if (!PackageHelper.fitsOnInternal(mContext, params)) { @@ -688,7 +688,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements final int sessionId; final PackageInstallerSession session; synchronized (mSessions) { - // Sanity check that installer isn't going crazy + // Check that the installer does not have too many active sessions. final int activeCount = getSessionCount(mSessions, callingUid); if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES) == PackageManager.PERMISSION_GRANTED) { diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 51164ba412b3..ca125320bbf2 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -249,6 +249,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private final PackageManagerService mPm; private final Handler mHandler; private final PackageSessionProvider mSessionProvider; + /** + * Note all calls must be done outside {@link #mLock} to prevent lock inversion. + */ private final StagingManager mStagingManager; final int sessionId; @@ -389,6 +392,20 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private String mStagedSessionErrorMessage; /** + * The callback to run when pre-reboot verification has ended. Used by {@link #abandonStaged()} + * to delay session clean-up until it is safe to do so. + */ + @GuardedBy("mLock") + @Nullable + private Runnable mPendingAbandonCallback; + /** + * {@code true} if pre-reboot verification is ongoing which means it is not safe for + * {@link #abandon()} to clean up staging directories. + */ + @GuardedBy("mLock") + private boolean mInPreRebootVerification; + + /** * Path to the validated base APK for this session, which may point at an * APK inside the session (when the session defines the base), or it may * point at the existing base APK (when adding splits to an existing app). @@ -978,7 +995,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private ParcelFileDescriptor doWriteInternal(String name, long offsetBytes, long lengthBytes, ParcelFileDescriptor incomingFd) throws IOException { - // Quick sanity check of state, and allocate a pipe for ourselves. We + // Quick validity check of state, and allocate a pipe for ourselves. We // then do heavy disk allocation outside the lock, but this open pipe // will block any attempted install transitions. final RevocableFileDescriptor fd; @@ -1454,26 +1471,54 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // TODO(patb): since the work done here for a parent session in a multi-package install is // mostly superficial, consider splitting this method for the parent and // single / child sessions. - synchronized (mLock) { - if (mCommitted) { - return true; + try { + synchronized (mLock) { + if (mCommitted) { + return true; + } + // Read transfers from the original owner stay open, but as the session's data + // cannot be modified anymore, there is no leak of information. For staged sessions, + // further validation is performed by the staging manager. + if (!params.isMultiPackage) { + if (!prepareDataLoaderLocked()) { + return false; + } + + if (isApexInstallation()) { + validateApexInstallLocked(); + } else { + validateApkInstallLocked(); + } + } } - if (!streamAndValidateLocked()) { - return false; + if (params.isStaged) { + mStagingManager.checkNonOverlappingWithStagedSessions(this); } - // Client staging is fully done at this point - mClientProgress = 1f; - computeProgressLocked(true); + synchronized (mLock) { + if (mDestroyed) { + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + "Session destroyed"); + } + // Client staging is fully done at this point + mClientProgress = 1f; + computeProgressLocked(true); - // This ongoing commit should keep session active, even though client - // will probably close their end. - mActiveCount.incrementAndGet(); + // This ongoing commit should keep session active, even though client + // will probably close their end. + mActiveCount.incrementAndGet(); - mCommitted = true; + mCommitted = true; + } + return true; + } catch (PackageManagerException e) { + throw onSessionValidationFailure(e); + } catch (Throwable e) { + // Convert all exceptions into package manager exceptions as only those are handled + // in the code above. + throw onSessionValidationFailure(new PackageManagerException(e)); } - return true; } @GuardedBy("mLock") @@ -1511,44 +1556,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } - /** - * Prepare DataLoader and stream content for DataLoader sessions. - * Validate the contents of all session. - * - * @return false if the data loader could not be prepared. - * @throws PackageManagerException when an unrecoverable exception is encountered - */ - @GuardedBy("mLock") - private boolean streamAndValidateLocked() throws PackageManagerException { - try { - // Read transfers from the original owner stay open, but as the session's data cannot - // be modified anymore, there is no leak of information. For staged sessions, further - // validation is performed by the staging manager. - if (!params.isMultiPackage) { - if (!prepareDataLoaderLocked()) { - return false; - } - - if (isApexInstallation()) { - validateApexInstallLocked(); - } else { - validateApkInstallLocked(); - } - } - - if (params.isStaged) { - mStagingManager.checkNonOverlappingWithStagedSessions(this); - } - return true; - } catch (PackageManagerException e) { - throw onSessionValidationFailure(e); - } catch (Throwable e) { - // Convert all exceptions into package manager exceptions as only those are handled - // in the code above. - throw onSessionValidationFailure(new PackageManagerException(e)); - } - } - private PackageManagerException onSessionValidationFailure(PackageManagerException e) { onSessionValidationFailure(e.error, ExceptionUtils.getCompleteMessage(e)); return e; @@ -1571,7 +1578,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, msgWithErrorCode); // TODO(b/136257624): Remove this once all verification logic has been transferred out // of StagingManager. - mStagingManager.notifyVerificationComplete(sessionId); + mStagingManager.notifyVerificationComplete(this); } else { // Dispatch message to remove session from PackageInstallerService. dispatchSessionFinished(error, msg, null); @@ -1837,21 +1844,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { throws PackageManagerException { assertNotLocked("makeSessionActive"); - synchronized (mLock) { - if (mRelinquished) { - throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, - "Session relinquished"); - } - if (mDestroyed) { - throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, - "Session destroyed"); - } - if (!mSealed) { - throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, - "Session not sealed"); - } - } - // TODO(b/159331446): Move this to makeSessionActiveForInstall and update javadoc if (!params.isMultiPackage && needToAskForPermissions()) { // User needs to confirm installation; @@ -1881,6 +1873,19 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private PackageManagerService.VerificationParams makeVerificationParamsLocked() throws PackageManagerException { + if (mRelinquished) { + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + "Session relinquished"); + } + if (mDestroyed) { + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + "Session destroyed"); + } + if (!mSealed) { + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + "Session not sealed"); + } + // TODO(b/136257624): Some logic in this if block probably belongs in // makeInstallParams(). if (!params.isMultiPackage && !isApexInstallation()) { @@ -2787,14 +2792,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } private void abandonStaged() { + final Runnable r; synchronized (mLock) { - if (mDestroyed) { - // If a user abandons staged session in an unsafe state, then system will try to - // abandon the destroyed staged session when it is safe on behalf of the user. - assertCallerIsOwnerOrRootOrSystemLocked(); - } else { - assertCallerIsOwnerOrRootLocked(); - } + assertCallerIsOwnerOrRootLocked(); if (isStagedAndInTerminalState()) { // We keep the session in the database if it's in a finalized state. It will be // removed by PackageInstallerService when the last update time is old enough. @@ -2803,17 +2803,25 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return; } mDestroyed = true; - if (mCommitted) { - if (!mStagingManager.abortCommittedSessionLocked(this)) { - // Do not clean up the staged session from system. It is not safe yet. - mCallback.onStagedSessionChanged(this); - return; + boolean isCommitted = mCommitted; + List<PackageInstallerSession> childSessions = getChildSessionsLocked(); + r = () -> { + assertNotLocked("abandonStaged"); + if (isCommitted) { + mStagingManager.abortCommittedSession(this); } + cleanStageDir(childSessions); + destroyInternal(); + dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null); + }; + if (mInPreRebootVerification) { + // Pre-reboot verification is ongoing. It is not safe to clean up the session yet. + mPendingAbandonCallback = r; + mCallback.onStagedSessionChanged(this); + return; } - cleanStageDir(getChildSessionsLocked()); - destroyInternal(); } - dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null); + r.run(); } @Override @@ -2830,6 +2838,50 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + /** + * Notified by the staging manager that pre-reboot verification is about to start. The return + * value should be checked to decide whether it is OK to start pre-reboot verification. In + * the case of a destroyed session, {@code false} is returned and there is no need to start + * pre-reboot verification. + */ + boolean notifyStagedStartPreRebootVerification() { + synchronized (mLock) { + if (mInPreRebootVerification) { + throw new IllegalStateException("Pre-reboot verification has started"); + } + if (mDestroyed) { + return false; + } + mInPreRebootVerification = true; + return true; + } + } + + private void dispatchPendingAbandonCallback() { + final Runnable callback; + synchronized (mLock) { + callback = mPendingAbandonCallback; + mPendingAbandonCallback = null; + } + if (callback != null) { + callback.run(); + } + } + + /** + * Notified by the staging manager that pre-reboot verification has ended. Now it is safe to + * clean up the session if {@link #abandon()} has been called previously. + */ + void notifyStagedEndPreRebootVerification() { + synchronized (mLock) { + if (!mInPreRebootVerification) { + throw new IllegalStateException("Pre-reboot verification not started"); + } + mInPreRebootVerification = false; + } + dispatchPendingAbandonCallback(); + } + @Override public boolean isMultiPackage() { return params.isMultiPackage; @@ -3744,7 +3796,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { out.endTag(null, TAG_SESSION); } - // Sanity check to be performed when the session is restored from an external file. Only one + // Validity check to be performed when the session is restored from an external file. Only one // of the session states should be true, or none of them. private static boolean isStagedSessionStateValid(boolean isReady, boolean isApplied, boolean isFailed) { diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java index 3614cc047bf8..2bbca79741bd 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java @@ -67,7 +67,6 @@ public class PackageManagerShellCommandDataLoader extends DataLoaderService { } } - // Sanity check. if (sShellCommands.size() > TOO_MANY_PENDING_SHELL_COMMANDS) { Slog.e(TAG, "Too many pending shell commands: " + sShellCommands.size()); } diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 0c4eaec32ba5..462b21535371 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -60,7 +60,6 @@ import android.util.ArraySet; import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; -import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.apk.ApkSignatureVerifier; @@ -1028,22 +1027,12 @@ public class StagingManager { /** * <p>Abort committed staged session - * - * <p>This method must be called while holding {@link PackageInstallerSession#mLock}. - * - * <p>The method returns {@code false} to indicate it is not safe to clean up the session from - * system yet. When it is safe, the method returns {@code true}. - * - * <p> When it is safe to clean up, {@link StagingManager} will call - * {@link PackageInstallerSession#abandon()} on the session again. - * - * @return {@code true} if it is safe to cleanup the session resources, otherwise {@code false}. */ - boolean abortCommittedSessionLocked(@NonNull PackageInstallerSession session) { + void abortCommittedSession(@NonNull PackageInstallerSession session) { int sessionId = session.sessionId; - if (session.isStagedSessionApplied()) { - Slog.w(TAG, "Cannot abort applied session : " + sessionId); - return false; + if (session.isStagedAndInTerminalState()) { + Slog.w(TAG, "Cannot abort session in final state: " + sessionId); + return; } if (!session.isDestroyed()) { throw new IllegalStateException("Committed session must be destroyed before aborting it" @@ -1051,15 +1040,7 @@ public class StagingManager { } if (getStagedSession(sessionId) == null) { Slog.w(TAG, "Session " + sessionId + " has been abandoned already"); - return false; - } - - // If pre-reboot verification is running, then return false. StagingManager will call - // abandon again when pre-reboot verification ends. - if (mPreRebootVerificationHandler.isVerificationRunning(sessionId)) { - Slog.w(TAG, "Session " + sessionId + " aborted before pre-reboot " - + "verification completed."); - return false; + return; } // A session could be marked ready once its pre-reboot verification ends @@ -1075,7 +1056,6 @@ public class StagingManager { // Session was successfully aborted from apexd (if required) and pre-reboot verification // is also complete. It is now safe to clean up the session from system. abortSession(session); - return true; } /** @@ -1264,8 +1244,8 @@ public class StagingManager { // TODO(b/136257624): Temporary API to let PMS communicate with StagingManager. When all // verification logic is extracted out of StagingManager into PMS, we can remove // this. - void notifyVerificationComplete(int sessionId) { - mPreRebootVerificationHandler.onPreRebootVerificationComplete(sessionId); + void notifyVerificationComplete(PackageInstallerSession session) { + mPreRebootVerificationHandler.onPreRebootVerificationComplete(session); } // TODO(b/136257624): Temporary API to let PMS communicate with StagingManager. When all @@ -1279,8 +1259,6 @@ public class StagingManager { // Hold session ids before handler gets ready to do the verification. private IntArray mPendingSessionIds; private boolean mIsReady; - @GuardedBy("mVerificationRunning") - private final SparseBooleanArray mVerificationRunning = new SparseBooleanArray(); PreRebootVerificationHandler(Looper looper) { super(looper); @@ -1316,7 +1294,7 @@ public class StagingManager { } if (session.isDestroyed() || session.isStagedSessionFailed()) { // No point in running verification on a destroyed/failed session - onPreRebootVerificationComplete(sessionId); + onPreRebootVerificationComplete(session); return; } switch (msg.what) { @@ -1357,15 +1335,10 @@ public class StagingManager { } PackageInstallerSession session = getStagedSession(sessionId); - synchronized (mVerificationRunning) { - // Do not start verification on a session that has been abandoned - if (session == null || session.isDestroyed()) { - return; - } + if (session != null && session.notifyStagedStartPreRebootVerification()) { Slog.d(TAG, "Starting preRebootVerification for session " + sessionId); - mVerificationRunning.put(sessionId, true); + obtainMessage(MSG_PRE_REBOOT_VERIFICATION_START, sessionId, 0).sendToTarget(); } - obtainMessage(MSG_PRE_REBOOT_VERIFICATION_START, sessionId, 0).sendToTarget(); } private void onPreRebootVerificationFailure(PackageInstallerSession session, @@ -1376,28 +1349,14 @@ public class StagingManager { // failed on next step and staging directory for session will be deleted. } session.setStagedSessionFailed(errorCode, errorMessage); - onPreRebootVerificationComplete(session.sessionId); + onPreRebootVerificationComplete(session); } // Things to do when pre-reboot verification completes for a particular sessionId - private void onPreRebootVerificationComplete(int sessionId) { - // Remove it from mVerificationRunning so that verification is considered complete - synchronized (mVerificationRunning) { - Slog.d(TAG, "Stopping preRebootVerification for session " + sessionId); - mVerificationRunning.delete(sessionId); - } - // Check if the session was destroyed while pre-reboot verification was running. If so, - // abandon it again. - PackageInstallerSession session = getStagedSession(sessionId); - if (session != null && session.isDestroyed()) { - session.abandon(); - } - } - - private boolean isVerificationRunning(int sessionId) { - synchronized (mVerificationRunning) { - return mVerificationRunning.get(sessionId); - } + private void onPreRebootVerificationComplete(PackageInstallerSession session) { + int sessionId = session.sessionId; + Slog.d(TAG, "Stopping preRebootVerification for session " + sessionId); + session.notifyStagedEndPreRebootVerification(); } private void notifyPreRebootVerification_Start_Complete(int sessionId) { @@ -1516,7 +1475,7 @@ public class StagingManager { // or activate its apex, there won't be any files to work with as they will be cleaned // up by the system as part of abandonment. If session is abandoned before this point, // then the session is already destroyed and cannot be marked ready anymore. - onPreRebootVerificationComplete(session.sessionId); + onPreRebootVerificationComplete(session); // Proactively mark session as ready before calling apexd. Although this call order // looks counter-intuitive, this is the easiest way to ensure that session won't end up diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index ae2b040d0a89..e1cd9e334f4c 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -31,6 +31,7 @@ import android.annotation.UserIdInt; import android.app.AppOpsManager; import android.app.AppOpsManagerInternal; import android.content.BroadcastReceiver; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -242,8 +243,9 @@ public final class PermissionPolicyService extends SystemService { public void onReceive(Context context, Intent intent) { boolean hasSetupRun = true; try { - hasSetupRun = Settings.Secure.getInt(getContext().getContentResolver(), - Settings.Secure.USER_SETUP_COMPLETE) != 0; + final ContentResolver cr = getContext().getContentResolver(); + hasSetupRun = Settings.Secure.getIntForUser(cr, + Settings.Secure.USER_SETUP_COMPLETE, cr.getUserId()) != 0; } catch (Settings.SettingNotFoundException e) { // Ignore error, assume setup has run } diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java index aee3d8d3499b..b68c54fc6365 100644 --- a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java +++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java @@ -25,6 +25,7 @@ import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.timezonedetector.TimeZoneCapabilities; import android.app.timezonedetector.TimeZoneConfiguration; +import android.os.UserHandle; import java.util.Objects; @@ -56,6 +57,12 @@ public final class ConfigurationInternal { return mUserId; } + /** Returns the handle of the user this configuration is associated with. */ + @NonNull + public UserHandle getUserHandle() { + return UserHandle.of(mUserId); + } + /** Returns true if the user allowed to modify time zone configuration. */ public boolean isUserConfigAllowed() { return mUserConfigAllowed; @@ -198,13 +205,13 @@ public final class ConfigurationInternal { @Override public String toString() { - return "TimeZoneDetectorConfiguration{" + return "ConfigurationInternal{" + "mUserId=" + mUserId - + "mUserConfigAllowed=" + mUserConfigAllowed - + "mAutoDetectionSupported=" + mAutoDetectionSupported - + "mAutoDetectionEnabled=" + mAutoDetectionEnabled - + "mLocationEnabled=" + mLocationEnabled - + "mGeoDetectionEnabled=" + mGeoDetectionEnabled + + ", mUserConfigAllowed=" + mUserConfigAllowed + + ", mAutoDetectionSupported=" + mAutoDetectionSupported + + ", mAutoDetectionEnabled=" + mAutoDetectionEnabled + + ", mLocationEnabled=" + mLocationEnabled + + ", mGeoDetectionEnabled=" + mGeoDetectionEnabled + '}'; } diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java index 3230ef192b4b..a8d5c0282025 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java @@ -23,7 +23,7 @@ import java.io.PrintWriter; import java.util.function.Consumer; import java.util.function.Supplier; -/** Implemented the shell command interface for {@link TimeZoneDetectorService}. */ +/** Implements the shell command interface for {@link TimeZoneDetectorService}. */ class TimeZoneDetectorShellCommand extends ShellCommand { private final TimeZoneDetectorService mInterface; diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 386f390c6cb9..89b108c24630 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -126,6 +126,8 @@ public class TrustManagerService extends SystemService { private static final String TRUST_TIMEOUT_ALARM_TAG = "TrustManagerService.trustTimeoutForUser"; private static final long TRUST_TIMEOUT_IN_MILLIS = 4 * 60 * 60 * 1000; + private static final String PRIV_NAMESPACE = "http://schemas.android.com/apk/prv/res/android"; + private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<>(); private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<>(); private final Receiver mReceiver = new Receiver(); @@ -811,8 +813,8 @@ public class TrustManagerService extends SystemService { TypedArray sa = res .obtainAttributes(attrs, com.android.internal.R.styleable.TrustAgent); cn = sa.getString(com.android.internal.R.styleable.TrustAgent_settingsActivity); - canUnlockProfile = sa.getBoolean( - com.android.internal.R.styleable.TrustAgent_unlockProfile, false); + canUnlockProfile = attrs.getAttributeBooleanValue( + PRIV_NAMESPACE, "unlockProfile", false); sa.recycle(); } catch (PackageManager.NameNotFoundException e) { caughtException = e; diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index aa8069a76330..8ccbd1166a44 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3488,7 +3488,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return false; } return mWmService.mDisplayWindowSettings.shouldShowImeLocked(this) - || mWmService.mForceDesktopModeOnExternalDisplays; + || forceDesktopMode(); + } + + boolean forceDesktopMode() { + return mWmService.mForceDesktopModeOnExternalDisplays && !isDefaultDisplay && !isPrivate(); } private void setInputMethodTarget(WindowState target, boolean targetWaitingAnim) { @@ -4542,7 +4546,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp boolean supportsSystemDecorations() { return (mWmService.mDisplayWindowSettings.shouldShowSystemDecorsLocked(this) || (mDisplay.getFlags() & FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0 - || mWmService.mForceDesktopModeOnExternalDisplays) + || forceDesktopMode()) // VR virtual display will be used to run and render 2D app within a VR experience. && mDisplayId != mWmService.mVr2dDisplayId // Do not show system decorations on untrusted virtual display. diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 4998624b9097..941db09f59bd 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -1528,7 +1528,7 @@ public class DisplayPolicy { if (mInputConsumer == null) { return; } - showNavigationBar(); + showSystemBars(); // Any user activity always causes us to show the // navigation controls, if they had been hidden. // We also clear the low profile and only content @@ -1563,13 +1563,13 @@ public class DisplayPolicy { } } - private void showNavigationBar() { + private void showSystemBars() { final InsetsSourceProvider provider = mDisplayContent.getInsetsStateController() .peekSourceProvider(ITYPE_NAVIGATION_BAR); final InsetsControlTarget target = provider != null ? provider.getControlTarget() : null; if (target != null) { - target.showInsets(Type.navigationBars(), false /* fromIme */); + target.showInsets(Type.systemBars(), false /* fromIme */); } } } diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index 0206787ef226..0f43e49b568b 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -330,10 +330,8 @@ public class DisplayRotation { // It's also not likely to rotate a TV screen. final boolean isTv = mContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_LEANBACK); - final boolean forceDesktopMode = - mService.mForceDesktopModeOnExternalDisplays && !isDefaultDisplay; mDefaultFixedToUserRotation = - (isCar || isTv || mService.mIsPc || forceDesktopMode) + (isCar || isTv || mService.mIsPc || mDisplayContent.forceDesktopMode()) // For debug purposes the next line turns this feature off with: // $ adb shell setprop config.override_forced_orient true // $ adb shell wm size reset diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java index df7c07055e87..c8c83a6e34f0 100644 --- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java +++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java @@ -248,7 +248,7 @@ class DisplayWindowSettings { writeSettingsIfNeeded(entry, displayInfo); } - private int getWindowingModeLocked(Entry entry, int displayId) { + private int getWindowingModeLocked(Entry entry, DisplayContent dc) { int windowingMode = entry != null ? entry.mWindowingMode : WindowConfiguration.WINDOWING_MODE_UNDEFINED; // This display used to be in freeform, but we don't support freeform anymore, so fall @@ -259,10 +259,8 @@ class DisplayWindowSettings { } // No record is present so use default windowing mode policy. if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) { - final boolean forceDesktopMode = mService.mForceDesktopModeOnExternalDisplays - && displayId != Display.DEFAULT_DISPLAY; windowingMode = mService.mAtmService.mSupportsFreeformWindowManagement - && (mService.mIsPc || forceDesktopMode) + && (mService.mIsPc || dc.forceDesktopMode()) ? WindowConfiguration.WINDOWING_MODE_FREEFORM : WindowConfiguration.WINDOWING_MODE_FULLSCREEN; } @@ -272,7 +270,7 @@ class DisplayWindowSettings { int getWindowingModeLocked(DisplayContent dc) { final DisplayInfo displayInfo = dc.getDisplayInfo(); final Entry entry = getEntry(displayInfo); - return getWindowingModeLocked(entry, dc.getDisplayId()); + return getWindowingModeLocked(entry, dc); } void setWindowingModeLocked(DisplayContent dc, int mode) { @@ -382,7 +380,7 @@ class DisplayWindowSettings { final Entry entry = getOrCreateEntry(displayInfo); // Setting windowing mode first, because it may override overscan values later. - dc.setWindowingMode(getWindowingModeLocked(entry, dc.getDisplayId())); + dc.setWindowingMode(getWindowingModeLocked(entry, dc)); dc.getDisplayRotation().restoreSettings(entry.mUserRotationMode, entry.mUserRotation, entry.mFixedToUserRotation); diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index 63a595e3bc17..d9290fb18f08 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -38,7 +38,6 @@ import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; -import android.util.SparseBooleanArray; import android.view.SurfaceControl; import android.window.ITaskOrganizer; import android.window.ITaskOrganizerController; @@ -54,7 +53,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; -import java.util.Set; import java.util.WeakHashMap; import java.util.function.Consumer; diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index e3112efdead2..f39fa1b7fbc8 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -16,7 +16,9 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -615,8 +617,8 @@ class TaskSnapshotController { return state.calculateInsets(frame, null /* ignoringVisibilityState */, false /* isScreenRound */, false /* alwaysConsumeSystemBars */, null /* displayCutout */, 0 /* legacySoftInputMode */, 0 /* legacyWindowFlags */, - 0 /* legacySystemUiFlags */, null /* typeSideMap */).getInsets( - WindowInsets.Type.systemBars()).toRect(); + 0 /* legacySystemUiFlags */, TYPE_APPLICATION, WINDOWING_MODE_UNDEFINED, + null /* typeSideMap */).getInsets(WindowInsets.Type.systemBars()).toRect(); } void dump(PrintWriter pw, String prefix) { diff --git a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java index 8d706cb960e9..609af8d5bf4d 100644 --- a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java +++ b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java @@ -79,23 +79,6 @@ public class NoOpAudioSystemAdapter extends AudioSystemAdapter { } @Override - public int setDevicesRoleForCapturePreset(int capturePreset, int role, - @NonNull List<AudioDeviceAttributes> devices) { - return AudioSystem.AUDIO_STATUS_OK; - } - - @Override - public int removeDevicesRoleForCapturePreset( - int capturePreset, int role, @NonNull List<AudioDeviceAttributes> devicesToRemove) { - return AudioSystem.AUDIO_STATUS_OK; - } - - @Override - public int clearDevicesRoleForCapturePreset(int capturePreset, int role) { - return AudioSystem.AUDIO_STATUS_OK; - } - - @Override public int setParameters(String keyValuePairs) { return AudioSystem.AUDIO_STATUS_OK; } diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TestState.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TestState.java new file mode 100644 index 000000000000..7049efa1cc2f --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TestState.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.timezonedetector; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; + +/** + * A test support class used for tracking a piece of state in test objects like fakes and mocks. + * State can optionally be initialized using {@link #init}, which sets the value to an initial + * value, but is not treated as a change. Calls to {@link #set} are tracked and can be checked for + * during tests. The change-tracking can be cleared by calling {@link #commitLatest}, which puts the + * object into an unchanged state and sets the initial value to the latest value passed to + * {@link #set}. + */ +public class TestState<T> { + private T mInitialValue; + private final ArrayList<T> mValues = new ArrayList<>(5); + + /** Sets the initial value for the state. */ + public void init(T value) { + mValues.clear(); + mInitialValue = value; + } + + /** Sets the latest value for the state. */ + public void set(T value) { + mValues.add(value); + } + + /** Returns {@code true} if {@link #set} has been called. */ + public boolean hasBeenSet() { + return mValues.size() > 0; + } + + /** Fails if {@link #set} has been called. */ + public void assertHasNotBeenSet() { + assertFalse(hasBeenSet()); + } + + /** Fails if {@link #set} has not been called. */ + public void assertHasBeenSet() { + assertTrue(hasBeenSet()); + } + + /** + * Clears tracked changes and re-initializes using the latest set value as the initial value. + */ + public void commitLatest() { + if (hasBeenSet()) { + mInitialValue = mValues.get(mValues.size() - 1); + mValues.clear(); + } + } + + /** Asserts the latest value passed to {@link #set} equals {@code expected}. */ + public void assertLatestEquals(T expected) { + assertEquals(expected, getLatest()); + } + + /** Asserts the number of times {@link #set} has been called. */ + public void assertChangeCount(int expectedCount) { + assertEquals(expectedCount, mValues.size()); + } + + /** + * Returns the latest value passed to {@link #set}. If {@link #set} hasn't been called then the + * initial value is returned. + */ + public T getLatest() { + if (hasBeenSet()) { + return mValues.get(mValues.size() - 1); + } + return mInitialValue; + } +} diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java index 2bee5e5e7295..1cdf19319209 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java @@ -54,7 +54,6 @@ import org.junit.Test; import java.io.StringWriter; import java.util.Arrays; import java.util.Collections; -import java.util.LinkedList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -994,55 +993,6 @@ public class TimeZoneDetectorStrategyImplTest { } } - /** Some piece of state that tests want to track. */ - private static class TestState<T> { - private T mInitialValue; - private LinkedList<T> mValues = new LinkedList<>(); - - void init(T value) { - mValues.clear(); - mInitialValue = value; - } - - void set(T value) { - mValues.addFirst(value); - } - - boolean hasBeenSet() { - return mValues.size() > 0; - } - - void assertHasNotBeenSet() { - assertFalse(hasBeenSet()); - } - - void assertHasBeenSet() { - assertTrue(hasBeenSet()); - } - - void commitLatest() { - if (hasBeenSet()) { - mInitialValue = mValues.getLast(); - mValues.clear(); - } - } - - void assertLatestEquals(T expected) { - assertEquals(expected, getLatest()); - } - - void assertChangeCount(int expectedCount) { - assertEquals(expectedCount, mValues.size()); - } - - public T getLatest() { - if (hasBeenSet()) { - return mValues.getFirst(); - } - return mInitialValue; - } - } - /** * A "fluent" class allows reuse of code in tests: initialization, simulation and verification * logic. diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index f8baf8497069..b496d0b1a646 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -28,6 +28,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER; import static android.os.Build.VERSION_CODES.P; import static android.os.Build.VERSION_CODES.Q; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.FLAG_PRIVATE; import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT; import static android.view.DisplayCutout.BOUNDS_POSITION_TOP; import static android.view.DisplayCutout.fromBoundingRect; @@ -95,6 +96,7 @@ import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.util.DisplayMetrics; import android.view.DisplayCutout; +import android.view.DisplayInfo; import android.view.Gravity; import android.view.IDisplayWindowRotationCallback; import android.view.IDisplayWindowRotationController; @@ -1522,6 +1524,28 @@ public class DisplayContentTests extends WindowTestsBase { dc.setWindowingMode(WINDOWING_MODE_FULLSCREEN); } + @Test + public void testForceDesktopMode() { + mWm.mForceDesktopModeOnExternalDisplays = true; + // Not applicable for default display + assertFalse(mDefaultDisplay.forceDesktopMode()); + + // Not applicable for private secondary display. + final DisplayInfo displayInfo = new DisplayInfo(); + displayInfo.copyFrom(mDisplayInfo); + displayInfo.flags = FLAG_PRIVATE; + final DisplayContent privateDc = createNewDisplay(displayInfo); + assertFalse(privateDc.forceDesktopMode()); + + // Applicable for public secondary display. + final DisplayContent publicDc = createNewDisplay(); + assertTrue(publicDc.forceDesktopMode()); + + // Make sure forceDesktopMode() is false when the force config is disabled. + mWm.mForceDesktopModeOnExternalDisplays = false; + assertFalse(publicDc.forceDesktopMode()); + } + private boolean isOptionsPanelAtRight(int displayId) { return (mWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT; } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 4ce9cb90b684..969016b1c017 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -5555,7 +5555,8 @@ public class TelephonyManager { * @param events The telephony state(s) of interest to the listener, * as a bitwise-OR combination of {@link PhoneStateListener} * LISTEN_ flags. - * @deprecated use {@link #listen(long, PhoneStateListener) instead. + * @deprecated use {@link #listen(long, PhoneStateListener) instead due to the event number + * limit increased to 64. */ @Deprecated public void listen(PhoneStateListener listener, int events) { @@ -5563,9 +5564,6 @@ public class TelephonyManager { } /** - * Since the limit of {@link PhoneStateListener} LISTEN_ flags is exceeded, use long type to - * extend it. - * * Registers a listener object to receive notification of changes * in specified telephony states. * <p> 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 254209aee450..17590723da8d 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 @@ -80,7 +80,7 @@ class OpenAppColdTest( noUncoveredRegions(Surface.ROTATION_0, rotation, bugId = 141361128) navBarLayerRotatesAndScales(Surface.ROTATION_0, rotation) statusBarLayerRotatesScales(Surface.ROTATION_0, rotation) - navBarLayerIsAlwaysVisible() + navBarLayerIsAlwaysVisible(enabled = rotation == Surface.ROTATION_0) statusBarLayerIsAlwaysVisible(enabled = false) wallpaperLayerBecomesInvisible() } 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 dda41a3021a0..afadb58eeed5 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 @@ -88,7 +88,7 @@ class OpenAppWarmTest( noUncoveredRegions(Surface.ROTATION_0, rotation, bugId = 141361128) navBarLayerRotatesAndScales(Surface.ROTATION_0, rotation) statusBarLayerRotatesScales(Surface.ROTATION_0, rotation) - navBarLayerIsAlwaysVisible(bugId = 140855415) + navBarLayerIsAlwaysVisible(enabled = rotation == Surface.ROTATION_0) statusBarLayerIsAlwaysVisible(enabled = false) wallpaperLayerBecomesInvisible() } diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 1588bf72c969..79f61bb791f6 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -2509,7 +2509,18 @@ public class WifiConfiguration implements Parcelable { @KeyMgmt.KeyMgmtScheme public int getAuthType() { if (allowedKeyManagement.cardinality() > 1) { - throw new IllegalStateException("More than one auth type set"); + if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) { + if (allowedKeyManagement.cardinality() == 2 + && allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { + return KeyMgmt.WPA_EAP; + } + if (allowedKeyManagement.cardinality() == 3 + && allowedKeyManagement.get(KeyMgmt.IEEE8021X) + && allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) { + return KeyMgmt.SUITE_B_192; + } + } + throw new IllegalStateException("Invalid auth type set: " + allowedKeyManagement); } if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { return KeyMgmt.WPA_PSK; diff --git a/wifi/java/android/net/wifi/util/SdkLevelUtil.java b/wifi/java/android/net/wifi/util/SdkLevelUtil.java new file mode 100644 index 000000000000..f29b0a6f3611 --- /dev/null +++ b/wifi/java/android/net/wifi/util/SdkLevelUtil.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi.util; + +import android.os.Build; + +/** + * Utility to check the SDK version of the device that the code is running on. + * + * This can be used to disable new Wifi APIs added in Mainline updates on older SDK versions. + * + * @hide + */ +public class SdkLevelUtil { + + /** This class is instantiable to allow easy mocking. */ + public SdkLevelUtil() { } + + /** Returns true if the Android platform SDK is at least "S", false otherwise. */ + public boolean isAtLeastS() { + // TODO(b/167575586): after S SDK finalization, this method should just be + // `return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;` + + // at least S: return true + // this condition only evaluates to true after S SDK finalization when VERSION_CODES.S + // is set to something like "31", before SDK finalization the value is "10000" + // Note that Build.VERSION_CODES.S is inlined at compile time. If it's inlined to 10000, + // this condition never evaluates to true. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + return true; + } + + // Assume for now that S = R + 1 + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) { + return true; + } + + // R: check CODENAME + // Before S SDK finalization, SDK_INT = R = 30 i.e. remains on the previous version + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) { + // CODENAME = "REL" on R release builds + // CODENAME = "S" on S development builds + return "S".equals(Build.VERSION.CODENAME); + } + + // older than R: return false + return false; + } +} diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java index a7b6765e886a..62220a6237b1 100644 --- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java @@ -22,6 +22,7 @@ import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OPEN; import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OWE; import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_PSK; import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_SAE; +import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_WAPI_CERT; import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_WAPI_PSK; import static org.junit.Assert.assertArrayEquals; @@ -537,4 +538,52 @@ public class WifiConfigurationTest { configuration.setSecurityParams(SECURITY_TYPE_EAP_SUITE_B); assertFalse(configuration.needsPreSharedKey()); } + + @Test + public void testGetAuthType() throws Exception { + WifiConfiguration configuration = new WifiConfiguration(); + + configuration.setSecurityParams(SECURITY_TYPE_PSK); + assertEquals(KeyMgmt.WPA_PSK, configuration.getAuthType()); + + configuration.setSecurityParams(SECURITY_TYPE_SAE); + assertEquals(KeyMgmt.SAE, configuration.getAuthType()); + + configuration.setSecurityParams(SECURITY_TYPE_WAPI_PSK); + assertEquals(KeyMgmt.WAPI_PSK, configuration.getAuthType()); + + configuration.setSecurityParams(SECURITY_TYPE_OPEN); + assertEquals(KeyMgmt.NONE, configuration.getAuthType()); + + configuration.setSecurityParams(SECURITY_TYPE_OWE); + assertEquals(KeyMgmt.OWE, configuration.getAuthType()); + + configuration.setSecurityParams(SECURITY_TYPE_EAP); + assertEquals(KeyMgmt.WPA_EAP, configuration.getAuthType()); + + configuration.setSecurityParams(SECURITY_TYPE_EAP_SUITE_B); + assertEquals(KeyMgmt.SUITE_B_192, configuration.getAuthType()); + + configuration.setSecurityParams(SECURITY_TYPE_WAPI_CERT); + assertEquals(KeyMgmt.WAPI_CERT, configuration.getAuthType()); + } + + @Test (expected = IllegalStateException.class) + public void testGetAuthTypeFailure1() throws Exception { + WifiConfiguration configuration = new WifiConfiguration(); + + configuration.setSecurityParams(SECURITY_TYPE_PSK); + configuration.allowedKeyManagement.set(KeyMgmt.IEEE8021X); + configuration.getAuthType(); + } + + @Test (expected = IllegalStateException.class) + public void testGetAuthTypeFailure2() throws Exception { + WifiConfiguration configuration = new WifiConfiguration(); + + configuration.allowedKeyManagement.set(KeyMgmt.IEEE8021X); + configuration.allowedKeyManagement.set(KeyMgmt.WPA_EAP); + configuration.allowedKeyManagement.set(KeyMgmt.SAE); + configuration.getAuthType(); + } } |