Loading core/api/current.txt +29 −0 Original line number Diff line number Diff line Loading @@ -11370,6 +11370,7 @@ package android.content { field public static final String SEARCH_SERVICE = "search"; field @FlaggedApi("android.os.security_state_service") public static final String SECURITY_STATE_SERVICE = "security_state"; field public static final String SENSOR_SERVICE = "sensor"; field @FlaggedApi("android.hardware.serial.flags.enable_serial_api") public static final String SERIAL_SERVICE = "serial"; field public static final String SHORTCUT_SERVICE = "shortcut"; field public static final String STATUS_BAR_SERVICE = "statusbar"; field public static final String STORAGE_SERVICE = "storage"; Loading Loading @@ -21316,6 +21317,34 @@ package android.hardware.lights { } package android.hardware.serial { @FlaggedApi("android.hardware.serial.flags.enable_serial_api") public final class SerialManager { method @NonNull public java.util.List<android.hardware.serial.SerialPort> getSerialPorts(); method public void registerSerialPortListener(@NonNull android.hardware.serial.SerialPortListener, @NonNull java.util.concurrent.Executor); method public void unregisterSerialPortListener(@NonNull android.hardware.serial.SerialPortListener); } @FlaggedApi("android.hardware.serial.flags.enable_serial_api") public final class SerialPort { method @NonNull public String getName(); method public int getProductId(); method public int getVendorId(); method public void requestOpen(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.hardware.serial.SerialPortResponse,java.lang.Exception>); field public static final int INVALID_ID = -1; // 0xffffffff } @FlaggedApi("android.hardware.serial.flags.enable_serial_api") public interface SerialPortListener { method public void onSerialPortConnected(@NonNull android.hardware.serial.SerialPort); method public void onSerialPortDisconnected(@NonNull android.hardware.serial.SerialPort); } @FlaggedApi("android.hardware.serial.flags.enable_serial_api") public final class SerialPortResponse { method @NonNull public android.os.ParcelFileDescriptor getFileDescriptor(); method @NonNull public android.hardware.serial.SerialPort getPort(); } } package android.hardware.usb { public class UsbAccessory implements android.os.Parcelable { core/java/android/app/SystemServiceRegistry.java +24 −9 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.app; import static android.app.appfunctions.flags.Flags.enableAppFunctionManager; import static android.hardware.serial.flags.Flags.enableSerialApi; import static android.provider.flags.Flags.newStoragePublicApi; import static android.server.Flags.removeGameManagerServiceFromWear; import static android.service.chooser.Flags.interactiveChooser; Loading Loading @@ -107,10 +108,8 @@ import android.devicelock.DeviceLockFrameworkInitializer; import android.graphics.fonts.FontManager; import android.hardware.ConsumerIrManager; import android.hardware.ISensorPrivacyManager; import android.hardware.ISerialManager; import android.hardware.SensorManager; import android.hardware.SensorPrivacyManager; import android.hardware.SerialManager; import android.hardware.SystemSensorManager; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.IAuthService; Loading Loading @@ -805,13 +804,29 @@ public final class SystemServiceRegistry { return new AdbManager(ctx, IAdbManager.Stub.asInterface(b)); }}); registerService(Context.SERIAL_SERVICE, SerialManager.class, new CachedServiceFetcher<SerialManager>() { if (enableSerialApi()) { registerService(Context.SERIAL_SERVICE, android.hardware.serial.SerialManager.class, new CachedServiceFetcher<android.hardware.serial.SerialManager>() { @Override public SerialManager createService(ContextImpl ctx) throws ServiceNotFoundException { public android.hardware.serial.SerialManager createService(ContextImpl ctx) throws ServiceNotFoundException { IBinder b = ServiceManager.getServiceOrThrow(Context.SERIAL_SERVICE); return new SerialManager(ctx, ISerialManager.Stub.asInterface(b)); }}); return new android.hardware.serial.SerialManager(ctx, android.hardware.serial.ISerialManager.Stub.asInterface(b)); } }); } else { registerService(Context.SERIAL_SERVICE, android.hardware.SerialManager.class, new CachedServiceFetcher<android.hardware.SerialManager>() { @Override public android.hardware.SerialManager createService(ContextImpl ctx) throws ServiceNotFoundException { IBinder b = ServiceManager.getServiceOrThrow(Context.SERIAL_SERVICE); return new android.hardware.SerialManager(ctx, android.hardware.ISerialManager.Stub.asInterface(b)); } }); } registerService(Context.VIBRATOR_MANAGER_SERVICE, VibratorManager.class, new CachedServiceFetcher<VibratorManager>() { Loading core/java/android/content/Context.java +4 −5 Original line number Diff line number Diff line Loading @@ -4427,7 +4427,7 @@ public abstract class Context { // @hide: SIP_SERVICE, USB_SERVICE, LAUNCHER_APPS_SERVICE, // @hide: SERIAL_SERVICE, SERIAL_SERVICE, // @hide: HDMI_CONTROL_SERVICE, INPUT_SERVICE, DISPLAY_SERVICE, Loading Loading @@ -5998,13 +5998,12 @@ public abstract class Context { /** * Use with {@link #getSystemService(String)} to retrieve a {@link * android.hardware.SerialManager} for access to serial ports. * android.hardware.serial.SerialManager} for access to serial ports. * * @see #getSystemService(String) * @see android.hardware.SerialManager * * @hide * @see android.hardware.serial.SerialManager */ @FlaggedApi(android.hardware.serial.flags.Flags.FLAG_ENABLE_SERIAL_API) public static final String SERIAL_SERVICE = "serial"; /** Loading core/java/android/hardware/OWNERS +4 −1 Original line number Diff line number Diff line Loading @@ -22,3 +22,6 @@ per-file OverlayProperties* = file:/graphics/java/android/graphics/OWNERS # Lut related files per-file *Lut* = file:/graphics/java/android/graphics/OWNERS # Serial per-file *Serial* = file:/core/java/android/hardware/serial/OWNERS core/java/android/hardware/serial/SerialManager.java 0 → 100644 +161 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.hardware.serial; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.SystemService; import android.content.Context; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; /** * This class allows you to communicate with Serial ports. */ @SystemService(Context.SERIAL_SERVICE) @FlaggedApi(android.hardware.serial.flags.Flags.FLAG_ENABLE_SERIAL_API) public final class SerialManager { private static final String TAG = "SerialManager"; @SuppressWarnings("unused") private final @NonNull Context mContext; private final @NonNull ISerialManager mService; @GuardedBy("mLock") private SerialPortServiceListener mServiceListener; @GuardedBy("mLock") private ArrayMap<SerialPortListener, Executor> mListeners; private final Object mLock = new Object(); /** @hide */ public SerialManager(@NonNull Context context, @NonNull ISerialManager service) { mContext = context; mService = service; } /** * Enumerates serial ports. */ @NonNull public List<SerialPort> getSerialPorts() { try { List<SerialPortInfo> infos = mService.getSerialPorts(); List<SerialPort> ports = new ArrayList<>(infos.size()); for (int i = 0; i < infos.size(); i++) { ports.add(new SerialPort(infos.get(i), mService)); } return Collections.unmodifiableList(ports); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Register a listener to monitor serial port connections and disconnections. */ public void registerSerialPortListener(@NonNull SerialPortListener listener, @NonNull Executor executor) { synchronized (mLock) { if (mServiceListener == null) { mServiceListener = new SerialPortServiceListener(); try { mService.registerSerialPortListener(mServiceListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } if (mListeners == null) { mListeners = new ArrayMap<>(); } if (mListeners.containsKey(listener)) { throw new IllegalStateException("Listener has already been registered."); } mListeners.put(listener, executor); } } /** * Unregister a listener that monitored serial port connections and disconnections. */ public void unregisterSerialPortListener(@NonNull SerialPortListener listener) { synchronized (mLock) { if (mListeners == null) { return; } mListeners.remove(listener); if (mListeners.isEmpty()) { if (mServiceListener != null) { try { mService.unregisterSerialPortListener(mServiceListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } finally { // If there was a RemoteException, the system server may have died, // and this listener probably became unregistered, so clear it for // re-registration. mServiceListener = null; } } } } } private class SerialPortServiceListener extends ISerialPortListener.Stub { @Override public void onSerialPortConnected(SerialPortInfo info) { SerialPort port = new SerialPort(info, mService); synchronized (mLock) { for (Map.Entry<SerialPortListener, Executor> e : mListeners.entrySet()) { Executor executor = e.getValue(); SerialPortListener listener = e.getKey(); try { executor.execute(() -> listener.onSerialPortConnected(port)); } catch (RuntimeException e2) { Slog.w(TAG, "Exception in listener", e2); } } } } @Override public void onSerialPortDisconnected(SerialPortInfo info) { SerialPort port = new SerialPort(info, mService); synchronized (mLock) { for (Map.Entry<SerialPortListener, Executor> e : mListeners.entrySet()) { Executor executor = e.getValue(); SerialPortListener listener = e.getKey(); try { executor.execute(() -> listener.onSerialPortDisconnected(port)); } catch (RuntimeException e2) { Slog.w(TAG, "Exception in listener", e2); } } } } } } Loading
core/api/current.txt +29 −0 Original line number Diff line number Diff line Loading @@ -11370,6 +11370,7 @@ package android.content { field public static final String SEARCH_SERVICE = "search"; field @FlaggedApi("android.os.security_state_service") public static final String SECURITY_STATE_SERVICE = "security_state"; field public static final String SENSOR_SERVICE = "sensor"; field @FlaggedApi("android.hardware.serial.flags.enable_serial_api") public static final String SERIAL_SERVICE = "serial"; field public static final String SHORTCUT_SERVICE = "shortcut"; field public static final String STATUS_BAR_SERVICE = "statusbar"; field public static final String STORAGE_SERVICE = "storage"; Loading Loading @@ -21316,6 +21317,34 @@ package android.hardware.lights { } package android.hardware.serial { @FlaggedApi("android.hardware.serial.flags.enable_serial_api") public final class SerialManager { method @NonNull public java.util.List<android.hardware.serial.SerialPort> getSerialPorts(); method public void registerSerialPortListener(@NonNull android.hardware.serial.SerialPortListener, @NonNull java.util.concurrent.Executor); method public void unregisterSerialPortListener(@NonNull android.hardware.serial.SerialPortListener); } @FlaggedApi("android.hardware.serial.flags.enable_serial_api") public final class SerialPort { method @NonNull public String getName(); method public int getProductId(); method public int getVendorId(); method public void requestOpen(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.hardware.serial.SerialPortResponse,java.lang.Exception>); field public static final int INVALID_ID = -1; // 0xffffffff } @FlaggedApi("android.hardware.serial.flags.enable_serial_api") public interface SerialPortListener { method public void onSerialPortConnected(@NonNull android.hardware.serial.SerialPort); method public void onSerialPortDisconnected(@NonNull android.hardware.serial.SerialPort); } @FlaggedApi("android.hardware.serial.flags.enable_serial_api") public final class SerialPortResponse { method @NonNull public android.os.ParcelFileDescriptor getFileDescriptor(); method @NonNull public android.hardware.serial.SerialPort getPort(); } } package android.hardware.usb { public class UsbAccessory implements android.os.Parcelable {
core/java/android/app/SystemServiceRegistry.java +24 −9 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.app; import static android.app.appfunctions.flags.Flags.enableAppFunctionManager; import static android.hardware.serial.flags.Flags.enableSerialApi; import static android.provider.flags.Flags.newStoragePublicApi; import static android.server.Flags.removeGameManagerServiceFromWear; import static android.service.chooser.Flags.interactiveChooser; Loading Loading @@ -107,10 +108,8 @@ import android.devicelock.DeviceLockFrameworkInitializer; import android.graphics.fonts.FontManager; import android.hardware.ConsumerIrManager; import android.hardware.ISensorPrivacyManager; import android.hardware.ISerialManager; import android.hardware.SensorManager; import android.hardware.SensorPrivacyManager; import android.hardware.SerialManager; import android.hardware.SystemSensorManager; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.IAuthService; Loading Loading @@ -805,13 +804,29 @@ public final class SystemServiceRegistry { return new AdbManager(ctx, IAdbManager.Stub.asInterface(b)); }}); registerService(Context.SERIAL_SERVICE, SerialManager.class, new CachedServiceFetcher<SerialManager>() { if (enableSerialApi()) { registerService(Context.SERIAL_SERVICE, android.hardware.serial.SerialManager.class, new CachedServiceFetcher<android.hardware.serial.SerialManager>() { @Override public SerialManager createService(ContextImpl ctx) throws ServiceNotFoundException { public android.hardware.serial.SerialManager createService(ContextImpl ctx) throws ServiceNotFoundException { IBinder b = ServiceManager.getServiceOrThrow(Context.SERIAL_SERVICE); return new SerialManager(ctx, ISerialManager.Stub.asInterface(b)); }}); return new android.hardware.serial.SerialManager(ctx, android.hardware.serial.ISerialManager.Stub.asInterface(b)); } }); } else { registerService(Context.SERIAL_SERVICE, android.hardware.SerialManager.class, new CachedServiceFetcher<android.hardware.SerialManager>() { @Override public android.hardware.SerialManager createService(ContextImpl ctx) throws ServiceNotFoundException { IBinder b = ServiceManager.getServiceOrThrow(Context.SERIAL_SERVICE); return new android.hardware.SerialManager(ctx, android.hardware.ISerialManager.Stub.asInterface(b)); } }); } registerService(Context.VIBRATOR_MANAGER_SERVICE, VibratorManager.class, new CachedServiceFetcher<VibratorManager>() { Loading
core/java/android/content/Context.java +4 −5 Original line number Diff line number Diff line Loading @@ -4427,7 +4427,7 @@ public abstract class Context { // @hide: SIP_SERVICE, USB_SERVICE, LAUNCHER_APPS_SERVICE, // @hide: SERIAL_SERVICE, SERIAL_SERVICE, // @hide: HDMI_CONTROL_SERVICE, INPUT_SERVICE, DISPLAY_SERVICE, Loading Loading @@ -5998,13 +5998,12 @@ public abstract class Context { /** * Use with {@link #getSystemService(String)} to retrieve a {@link * android.hardware.SerialManager} for access to serial ports. * android.hardware.serial.SerialManager} for access to serial ports. * * @see #getSystemService(String) * @see android.hardware.SerialManager * * @hide * @see android.hardware.serial.SerialManager */ @FlaggedApi(android.hardware.serial.flags.Flags.FLAG_ENABLE_SERIAL_API) public static final String SERIAL_SERVICE = "serial"; /** Loading
core/java/android/hardware/OWNERS +4 −1 Original line number Diff line number Diff line Loading @@ -22,3 +22,6 @@ per-file OverlayProperties* = file:/graphics/java/android/graphics/OWNERS # Lut related files per-file *Lut* = file:/graphics/java/android/graphics/OWNERS # Serial per-file *Serial* = file:/core/java/android/hardware/serial/OWNERS
core/java/android/hardware/serial/SerialManager.java 0 → 100644 +161 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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.hardware.serial; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.SystemService; import android.content.Context; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.Executor; /** * This class allows you to communicate with Serial ports. */ @SystemService(Context.SERIAL_SERVICE) @FlaggedApi(android.hardware.serial.flags.Flags.FLAG_ENABLE_SERIAL_API) public final class SerialManager { private static final String TAG = "SerialManager"; @SuppressWarnings("unused") private final @NonNull Context mContext; private final @NonNull ISerialManager mService; @GuardedBy("mLock") private SerialPortServiceListener mServiceListener; @GuardedBy("mLock") private ArrayMap<SerialPortListener, Executor> mListeners; private final Object mLock = new Object(); /** @hide */ public SerialManager(@NonNull Context context, @NonNull ISerialManager service) { mContext = context; mService = service; } /** * Enumerates serial ports. */ @NonNull public List<SerialPort> getSerialPorts() { try { List<SerialPortInfo> infos = mService.getSerialPorts(); List<SerialPort> ports = new ArrayList<>(infos.size()); for (int i = 0; i < infos.size(); i++) { ports.add(new SerialPort(infos.get(i), mService)); } return Collections.unmodifiableList(ports); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Register a listener to monitor serial port connections and disconnections. */ public void registerSerialPortListener(@NonNull SerialPortListener listener, @NonNull Executor executor) { synchronized (mLock) { if (mServiceListener == null) { mServiceListener = new SerialPortServiceListener(); try { mService.registerSerialPortListener(mServiceListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } if (mListeners == null) { mListeners = new ArrayMap<>(); } if (mListeners.containsKey(listener)) { throw new IllegalStateException("Listener has already been registered."); } mListeners.put(listener, executor); } } /** * Unregister a listener that monitored serial port connections and disconnections. */ public void unregisterSerialPortListener(@NonNull SerialPortListener listener) { synchronized (mLock) { if (mListeners == null) { return; } mListeners.remove(listener); if (mListeners.isEmpty()) { if (mServiceListener != null) { try { mService.unregisterSerialPortListener(mServiceListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } finally { // If there was a RemoteException, the system server may have died, // and this listener probably became unregistered, so clear it for // re-registration. mServiceListener = null; } } } } } private class SerialPortServiceListener extends ISerialPortListener.Stub { @Override public void onSerialPortConnected(SerialPortInfo info) { SerialPort port = new SerialPort(info, mService); synchronized (mLock) { for (Map.Entry<SerialPortListener, Executor> e : mListeners.entrySet()) { Executor executor = e.getValue(); SerialPortListener listener = e.getKey(); try { executor.execute(() -> listener.onSerialPortConnected(port)); } catch (RuntimeException e2) { Slog.w(TAG, "Exception in listener", e2); } } } } @Override public void onSerialPortDisconnected(SerialPortInfo info) { SerialPort port = new SerialPort(info, mService); synchronized (mLock) { for (Map.Entry<SerialPortListener, Executor> e : mListeners.entrySet()) { Executor executor = e.getValue(); SerialPortListener listener = e.getKey(); try { executor.execute(() -> listener.onSerialPortDisconnected(port)); } catch (RuntimeException e2) { Slog.w(TAG, "Exception in listener", e2); } } } } } }