diff options
49 files changed, 425 insertions, 1150 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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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; + } +} |