summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt32
-rw-r--r--api/system-current.txt6
-rw-r--r--api/test-current.txt10
-rw-r--r--core/java/android/app/ActivityView.java37
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java9
-rw-r--r--core/java/android/hardware/display/IDisplayManager.aidl3
-rw-r--r--core/java/android/hardware/display/VirtualDisplay.java12
-rw-r--r--core/java/android/hardware/hdmi/HdmiAudioSystemClient.java47
-rw-r--r--core/java/android/hardware/hdmi/HdmiControlManager.java13
-rw-r--r--core/java/android/hardware/hdmi/IHdmiControlService.aidl2
-rw-r--r--core/java/android/provider/Settings.java9
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java1
-rw-r--r--core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java9
-rw-r--r--libs/hwui/WebViewFunctorManager.cpp20
-rw-r--r--libs/hwui/WebViewFunctorManager.h9
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp2
-rw-r--r--libs/hwui/pipeline/skia/VkFunctorDrawable.cpp59
-rw-r--r--libs/hwui/pipeline/skia/VkFunctorDrawable.h12
-rw-r--r--libs/hwui/private/hwui/DrawVkInfo.h119
-rw-r--r--libs/hwui/private/hwui/WebViewFunctor.h13
-rw-r--r--libs/hwui/renderthread/RenderThread.h5
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp89
-rw-r--r--libs/hwui/renderthread/VulkanManager.h9
-rw-r--r--media/java/android/media/AudioFormat.java3
-rw-r--r--media/java/android/media/MediaPlayer2.java293
-rw-r--r--native/webview/plat_support/draw_fn.h31
-rw-r--r--native/webview/plat_support/draw_functor.cpp89
-rw-r--r--packages/SettingsLib/res/values/strings.xml2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java2
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java1
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java13
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java20
-rw-r--r--services/core/java/com/android/server/display/VirtualDisplayAdapter.java21
-rwxr-xr-xservices/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java43
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecController.java4
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java151
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java22
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecMessage.java16
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java90
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiUtils.java74
-rw-r--r--services/core/java/com/android/server/location/MockProvider.java1
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java38
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp18
48 files changed, 1174 insertions, 347 deletions
diff --git a/api/current.txt b/api/current.txt
index b3618601e1be..e2ea649e2242 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -25476,6 +25476,7 @@ package android.media {
method public java.lang.Object setAuxEffectSendLevel(float);
method public java.lang.Object setDataSource(android.media.DataSourceDesc);
method public java.lang.Object setDisplay(android.view.SurfaceHolder);
+ method public void setDrmEventCallback(java.util.concurrent.Executor, android.media.MediaPlayer2.DrmEventCallback);
method public java.lang.Object setNextDataSource(android.media.DataSourceDesc);
method public java.lang.Object setNextDataSources(java.util.List<android.media.DataSourceDesc>);
method public java.lang.Object setPlaybackParams(android.media.PlaybackParams);
@@ -25554,6 +25555,33 @@ package android.media {
field public static final int SEEK_PREVIOUS_SYNC = 0; // 0x0
}
+ public static class MediaPlayer2.DrmEventCallback {
+ ctor public MediaPlayer2.DrmEventCallback();
+ method public void onDrmConfig(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaDrm);
+ method public android.media.MediaPlayer2.DrmPreparationInfo onDrmInfo(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaPlayer2.DrmInfo);
+ method public byte[] onDrmKeyRequest(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaDrm.KeyRequest);
+ method public void onDrmPrepared(android.media.MediaPlayer2, android.media.DataSourceDesc, int, byte[]);
+ }
+
+ public static final class MediaPlayer2.DrmInfo {
+ method public java.util.Map<java.util.UUID, byte[]> getPssh();
+ method public java.util.List<java.util.UUID> getSupportedSchemes();
+ }
+
+ public static final class MediaPlayer2.DrmPreparationInfo {
+ }
+
+ public static final class MediaPlayer2.DrmPreparationInfo.Builder {
+ ctor public MediaPlayer2.DrmPreparationInfo.Builder();
+ method public android.media.MediaPlayer2.DrmPreparationInfo build();
+ method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setInitData(byte[]);
+ method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeySetId(byte[]);
+ method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeyType(int);
+ method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setMimeType(java.lang.String);
+ method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setOptionalParameters(java.util.Map<java.lang.String, java.lang.String>);
+ method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setUuid(java.util.UUID);
+ }
+
public static class MediaPlayer2.EventCallback {
ctor public MediaPlayer2.EventCallback();
method public void onCallCompleted(android.media.MediaPlayer2, android.media.DataSourceDesc, int, int);
@@ -25581,6 +25609,10 @@ package android.media {
field public static final java.lang.String WIDTH = "android.media.mediaplayer.width";
}
+ public static final class MediaPlayer2.NoDrmSchemeException extends android.media.MediaDrmException {
+ ctor public MediaPlayer2.NoDrmSchemeException(java.lang.String);
+ }
+
public static class MediaPlayer2.TrackInfo {
method public android.media.MediaFormat getFormat();
method public java.lang.String getLanguage();
diff --git a/api/system-current.txt b/api/system-current.txt
index 5fac1ee13e2c..276be9dd746d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4864,6 +4864,7 @@ package android.permission {
method public abstract int onCountPermissionApps(java.util.List<java.lang.String>, boolean, boolean);
method public abstract java.util.List<android.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(java.lang.String);
method public abstract void onGetRuntimePermissionsBackup(android.os.UserHandle, java.io.OutputStream);
+ method public abstract java.util.List<android.permission.RuntimePermissionUsageInfo> onPermissionUsageResult(boolean, long);
method public abstract void onRevokeRuntimePermission(java.lang.String, java.lang.String);
method public abstract java.util.Map<java.lang.String, java.util.List<java.lang.String>> onRevokeRuntimePermissions(java.util.Map<java.lang.String, java.util.List<java.lang.String>>, boolean, int, java.lang.String);
field public static final java.lang.String SERVICE_INTERFACE = "android.permission.PermissionControllerService";
@@ -4892,11 +4893,12 @@ package android.permission {
public final class RuntimePermissionUsageInfo implements android.os.Parcelable {
ctor public RuntimePermissionUsageInfo(java.lang.CharSequence, int);
method public int describeContents();
- method public java.lang.CharSequence getName();
method public int getAppAccessCount();
+ method public java.lang.CharSequence getName();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.permission.RuntimePermissionUsageInfo> CREATOR;
}
+
}
package android.permissionpresenterservice {
@@ -7252,7 +7254,6 @@ package android.telephony.ims {
method public void callSessionInviteParticipantsRequestDelivered();
method public void callSessionInviteParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionMayHandover(int, int);
- method public void callSessionRttAudioIndicatorChanged(android.telephony.ims.ImsStreamMediaProfile);
method public void callSessionMergeComplete(android.telephony.ims.stub.ImsCallSessionImplBase);
method public void callSessionMergeFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionMergeStarted(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
@@ -7263,6 +7264,7 @@ package android.telephony.ims {
method public void callSessionResumeFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionResumeReceived(android.telephony.ims.ImsCallProfile);
method public void callSessionResumed(android.telephony.ims.ImsCallProfile);
+ method public void callSessionRttAudioIndicatorChanged(android.telephony.ims.ImsStreamMediaProfile);
method public void callSessionRttMessageReceived(java.lang.String);
method public void callSessionRttModifyRequestReceived(android.telephony.ims.ImsCallProfile);
method public void callSessionRttModifyResponseReceived(int);
diff --git a/api/test-current.txt b/api/test-current.txt
index fb50fa194a92..71f02b9bdc9a 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -945,6 +945,11 @@ package android.os {
field public static final android.os.Parcelable.Creator<android.os.IncidentReportArgs> CREATOR;
}
+ public final class MessageQueue {
+ method public int postSyncBarrier();
+ method public void removeSyncBarrier(int);
+ }
+
public final class NativeHandle implements java.io.Closeable {
ctor public NativeHandle();
ctor public NativeHandle(java.io.FileDescriptor, boolean);
@@ -957,11 +962,6 @@ package android.os {
method public boolean hasSingleFileDescriptor();
}
- public final class MessageQueue {
- method public int postSyncBarrier();
- method public void removeSyncBarrier(int);
- }
-
public final class PowerManager {
method public int getPowerSaveMode();
method public boolean setDynamicPowerSavings(boolean, int);
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 57132a72700d..ab8f234766d6 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -16,6 +16,10 @@
package android.app;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
+
import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
import android.app.ActivityManager.StackInfo;
@@ -32,7 +36,6 @@ import android.util.Log;
import android.view.IWindowManager;
import android.view.InputDevice;
import android.view.MotionEvent;
-import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceHolder;
import android.view.SurfaceSession;
@@ -82,7 +85,6 @@ public class ActivityView extends ViewGroup {
private boolean mOpened; // Protected by mGuard.
private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
- private Surface mTmpSurface = new Surface();
/** The ActivityView is only allowed to contain one task. */
private final boolean mSingleTaskInstance;
@@ -319,20 +321,20 @@ public class ActivityView extends ViewGroup {
private class SurfaceCallback implements SurfaceHolder.Callback {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
- mTmpSurface = new Surface();
if (mVirtualDisplay == null) {
initVirtualDisplay(new SurfaceSession());
if (mVirtualDisplay != null && mActivityViewCallback != null) {
mActivityViewCallback.onActivityViewReady(ActivityView.this);
}
} else {
- // TODO (b/119209373): DisplayManager determines if a VirtualDisplay is on by
- // whether it has a surface. Setting a fake surface here so DisplayManager will
- // consider this display on.
- mVirtualDisplay.setSurface(mTmpSurface);
mTmpTransaction.reparent(mRootSurfaceControl,
mSurfaceView.getSurfaceControl().getHandle()).apply();
}
+
+ if (mVirtualDisplay != null) {
+ mVirtualDisplay.setDisplayState(true);
+ }
+
updateLocation();
}
@@ -346,10 +348,8 @@ public class ActivityView extends ViewGroup {
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
- mTmpSurface.release();
- mTmpSurface = null;
if (mVirtualDisplay != null) {
- mVirtualDisplay.setSurface(null);
+ mVirtualDisplay.setDisplayState(false);
}
cleanTapExcludeRegion();
}
@@ -370,15 +370,11 @@ public class ActivityView extends ViewGroup {
final int height = mSurfaceView.getHeight();
final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
- // TODO (b/119209373): DisplayManager determines if a VirtualDisplay is on by
- // whether it has a surface. Setting a fake surface here so DisplayManager will consider
- // this display on.
mVirtualDisplay = displayManager.createVirtualDisplay(
- DISPLAY_NAME + "@" + System.identityHashCode(this),
- width, height, getBaseDisplayDensity(), mTmpSurface,
- DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
- | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
- | DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL);
+ DISPLAY_NAME + "@" + System.identityHashCode(this), width, height,
+ getBaseDisplayDensity(), null,
+ VIRTUAL_DISPLAY_FLAG_PUBLIC | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
+ | VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL);
if (mVirtualDisplay == null) {
Log.e(TAG, "Failed to initialize ActivityView");
return;
@@ -443,11 +439,6 @@ public class ActivityView extends ViewGroup {
displayReleased = false;
}
- if (mTmpSurface != null) {
- mTmpSurface.release();
- mTmpSurface = null;
- }
-
if (displayReleased && mActivityViewCallback != null) {
mActivityViewCallback.onActivityViewDestroyed(this);
}
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index cda8498c4f01..7e45441c804a 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -436,6 +436,7 @@ public final class DisplayManagerGlobal {
public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) {
try {
mDm.setVirtualDisplaySurface(token, surface);
+ setVirtualDisplayState(token, surface != null);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
@@ -458,6 +459,14 @@ public final class DisplayManagerGlobal {
}
}
+ void setVirtualDisplayState(IVirtualDisplayCallback token, boolean isOn) {
+ try {
+ mDm.setVirtualDisplayState(token, isOn);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
/**
* Gets the stable device display size, in pixels.
*/
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 2d81cdfec179..aae8afbcad49 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -82,6 +82,9 @@ interface IDisplayManager {
// No permissions required but must be same Uid as the creator.
void releaseVirtualDisplay(in IVirtualDisplayCallback token);
+ // No permissions required but must be same Uid as the creator.
+ void setVirtualDisplayState(in IVirtualDisplayCallback token, boolean isOn);
+
// Get a stable metric for the device's display size. No permissions required.
Point getStableDisplaySize();
diff --git a/core/java/android/hardware/display/VirtualDisplay.java b/core/java/android/hardware/display/VirtualDisplay.java
index d35466605162..bf62c95cf6db 100644
--- a/core/java/android/hardware/display/VirtualDisplay.java
+++ b/core/java/android/hardware/display/VirtualDisplay.java
@@ -104,6 +104,18 @@ public final class VirtualDisplay {
}
}
+ /**
+ * Sets the on/off state for a virtual display.
+ *
+ * @param isOn Whether the display should be on or off.
+ * @hide
+ */
+ public void setDisplayState(boolean isOn) {
+ if (mToken != null) {
+ mGlobal.setVirtualDisplayState(mToken, isOn);
+ }
+ }
+
@Override
public String toString() {
return "VirtualDisplay{display=" + mDisplay + ", token=" + mToken
diff --git a/core/java/android/hardware/hdmi/HdmiAudioSystemClient.java b/core/java/android/hardware/hdmi/HdmiAudioSystemClient.java
index d382eb9310d9..bdd5ab67af48 100644
--- a/core/java/android/hardware/hdmi/HdmiAudioSystemClient.java
+++ b/core/java/android/hardware/hdmi/HdmiAudioSystemClient.java
@@ -15,10 +15,12 @@
*/
package android.hardware.hdmi;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
@@ -56,6 +58,21 @@ public final class HdmiAudioSystemClient extends HdmiClient {
mHandler = handler == null ? new Handler(Looper.getMainLooper()) : handler;
}
+ /**
+ * Callback interface used to get the set System Audio Mode result.
+ *
+ * @hide
+ */
+ // TODO(b/110094868): unhide and add @SystemApi for Q
+ public interface SetSystemAudioModeCallback {
+ /**
+ * Called when the input was changed.
+ *
+ * @param result the result of the set System Audio Mode
+ */
+ void onComplete(int result);
+ }
+
/** @hide */
// TODO(b/110094868): unhide and add @SystemApi for Q
@Override
@@ -117,4 +134,34 @@ public final class HdmiAudioSystemClient extends HdmiClient {
mPendingReportAudioStatus = true;
}
}
+
+ /**
+ * Set System Audio Mode on/off with audio system device.
+ *
+ * @param state true to set System Audio Mode on. False to set off.
+ * @param callback callback offer the setting result.
+ *
+ * @hide
+ */
+ // TODO(b/110094868): unhide and add @SystemApi for Q
+ public void setSystemAudioMode(boolean state, @NonNull SetSystemAudioModeCallback callback) {
+ // TODO(amyjojo): implement this when needed.
+ }
+
+ /**
+ * When device is switching to an audio only source, this method is called to broadcast
+ * a setSystemAudioMode on message to the HDMI CEC system without querying Active Source or
+ * TV supporting System Audio Control or not. This is to get volume control passthrough
+ * from STB even if TV does not support it.
+ *
+ * @hide
+ */
+ // TODO(b/110094868): unhide and add @SystemApi for Q
+ public void setSystemAudioModeOnForAudioOnlySource() {
+ try {
+ mService.setSystemAudioModeOnForAudioOnlySource();
+ } catch (RemoteException e) {
+ Log.d(TAG, "Failed to set System Audio Mode on for Audio Only source");
+ }
+ }
}
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index f5d288e6a233..be8009e6a966 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -432,6 +432,19 @@ public final class HdmiControlManager {
}
/**
+ * Get the physical address of the device.
+ *
+ * @hide
+ */
+ public int getPhysicalAddress() {
+ try {
+ return mService.getPhysicalAddress();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Listener used to get hotplug event from HDMI port.
*/
public interface HotplugEventListener {
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 2b8d00b73b7e..66bb084d5482 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -50,6 +50,7 @@ interface IHdmiControlService {
List<HdmiPortInfo> getPortInfo();
boolean canChangeSystemAudioMode();
boolean getSystemAudioMode();
+ int getPhysicalAddress();
void setSystemAudioMode(boolean enabled, IHdmiControlCallback callback);
void addSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener);
void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener);
@@ -73,4 +74,5 @@ interface IHdmiControlService {
void addHdmiMhlVendorCommandListener(IHdmiMhlVendorCommandListener listener);
void setStandbyMode(boolean isStandbyModeOn);
void reportAudioStatus(int deviceType, int volume, int maxVolume, boolean isMute);
+ void setSystemAudioModeOnForAudioOnlySource();
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 84825484c36d..10555fab0a8a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9381,6 +9381,15 @@ public final class Settings {
"hdmi_system_audio_control_enabled";
/**
+ * Whether HDMI Routing Control feature is enabled. If enabled, the switch device will
+ * route to the correct input source on receiving Routing Control related messages. If
+ * disabled, you can only switch the input via controls on this device.
+ * @hide
+ */
+ public static final String HDMI_CEC_SWITCH_ENABLED =
+ "hdmi_cec_switch_enabled";
+
+ /**
* Whether TV will automatically turn on upon reception of the CEC command
* &lt;Text View On&gt; or &lt;Image View On&gt;. (0 = false, 1 = true)
*
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 1ed5ce4a3929..341f345ce11f 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -270,6 +270,7 @@ public class SettingsBackupTest {
Settings.Global.GNSS_HAL_LOCATION_REQUEST_DURATION_MILLIS,
Settings.Global.GNSS_SATELLITE_BLACKLIST,
Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
+ Settings.Global.HDMI_CEC_SWITCH_ENABLED,
Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
Settings.Global.HDMI_CONTROL_ENABLED,
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
index 0dd9d0904746..64b3ba04e841 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
@@ -318,6 +318,15 @@ public class HdmiAudioSystemClientTest {
mMaxVolume = maxVolume;
mIsMute = isMute;
}
+
+ @Override
+ public void setSystemAudioModeOnForAudioOnlySource() {
+ }
+
+ @Override
+ public int getPhysicalAddress() {
+ return 0x0000;
+ }
}
}
diff --git a/libs/hwui/WebViewFunctorManager.cpp b/libs/hwui/WebViewFunctorManager.cpp
index 9170d6d1dc50..68541b4b31f0 100644
--- a/libs/hwui/WebViewFunctorManager.cpp
+++ b/libs/hwui/WebViewFunctorManager.cpp
@@ -86,6 +86,26 @@ void WebViewFunctor::drawGl(const DrawGlInfo& drawInfo) {
mCallbacks.gles.draw(mFunctor, mData, drawInfo);
}
+void WebViewFunctor::initVk(const VkFunctorInitParams& params) {
+ ATRACE_NAME("WebViewFunctor::initVk");
+ if (!mHasContext) {
+ mHasContext = true;
+ } else {
+ return;
+ }
+ mCallbacks.vk.initialize(mFunctor, mData, params);
+}
+
+void WebViewFunctor::drawVk(const VkFunctorDrawParams& params) {
+ ATRACE_NAME("WebViewFunctor::drawVk");
+ mCallbacks.vk.draw(mFunctor, mData, params);
+}
+
+void WebViewFunctor::postDrawVk() {
+ ATRACE_NAME("WebViewFunctor::postDrawVk");
+ mCallbacks.vk.postDraw(mFunctor, mData);
+}
+
void WebViewFunctor::destroyContext() {
if (mHasContext) {
mHasContext = false;
diff --git a/libs/hwui/WebViewFunctorManager.h b/libs/hwui/WebViewFunctorManager.h
index 1719ce7cca75..2846cb1f087b 100644
--- a/libs/hwui/WebViewFunctorManager.h
+++ b/libs/hwui/WebViewFunctorManager.h
@@ -42,6 +42,12 @@ public:
void drawGl(const DrawGlInfo& drawInfo) const { mReference.drawGl(drawInfo); }
+ void initVk(const VkFunctorInitParams& params) { mReference.initVk(params); }
+
+ void drawVk(const VkFunctorDrawParams& params) { mReference.drawVk(params); }
+
+ void postDrawVk() { mReference.postDrawVk(); }
+
private:
friend class WebViewFunctor;
@@ -53,6 +59,9 @@ public:
int id() const { return mFunctor; }
void sync(const WebViewSyncData& syncData) const;
void drawGl(const DrawGlInfo& drawInfo);
+ void initVk(const VkFunctorInitParams& params);
+ void drawVk(const VkFunctorDrawParams& params);
+ void postDrawVk();
void destroyContext();
sp<Handle> createHandle() {
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 6eefed959913..d54275fe7e19 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -125,8 +125,6 @@ void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor,
uirenderer::GlFunctorLifecycleListener* listener) {
FunctorDrawable* functorDrawable;
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
- // TODO(cblume) use VkFunctorDrawable instead of VkInteropFunctorDrawable here when the
- // interop is disabled/moved.
functorDrawable = mDisplayList->allocateDrawable<VkInteropFunctorDrawable>(
functor, listener, asSkCanvas());
} else {
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
index 156f74a611a7..2f8d381f15f5 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
@@ -17,6 +17,8 @@
#include "VkFunctorDrawable.h"
#include <private/hwui/DrawVkInfo.h>
+#include "renderthread/VulkanManager.h"
+#include "renderthread/RenderThread.h"
#include <GrBackendDrawableInfo.h>
#include <SkImage.h>
#include <utils/Color.h>
@@ -31,34 +33,58 @@ namespace android {
namespace uirenderer {
namespace skiapipeline {
-VkFunctorDrawHandler::VkFunctorDrawHandler(Functor* functor) : INHERITED(), mFunctor(functor) {}
+VkFunctorDrawHandler::VkFunctorDrawHandler(sp<WebViewFunctor::Handle> functor_handle,
+ const SkMatrix& matrix, const SkIRect& clip,
+ const SkImageInfo& image_info)
+ : INHERITED()
+ , mFunctorHandle(functor_handle)
+ , mMatrix(matrix)
+ , mClip(clip)
+ , mImageInfo(image_info) {}
VkFunctorDrawHandler::~VkFunctorDrawHandler() {
- // TODO(cblume) Fill in the DrawVkInfo parameters.
- (*mFunctor)(DrawVkInfo::kModePostComposite, nullptr);
+ mFunctorHandle->postDrawVk();
}
void VkFunctorDrawHandler::draw(const GrBackendDrawableInfo& info) {
ATRACE_CALL();
+ if (!renderthread::RenderThread::isCurrent())
+ LOG_ALWAYS_FATAL("VkFunctorDrawHandler::draw not called on render thread");
GrVkDrawableInfo vulkan_info;
if (!info.getVkDrawableInfo(&vulkan_info)) {
return;
}
+ renderthread::VulkanManager& vk_manager =
+ renderthread::RenderThread::getInstance().vulkanManager();
+ mFunctorHandle->initVk(vk_manager.getVkFunctorInitParams());
- DrawVkInfo draw_vk_info;
- // TODO(cblume) Fill in the rest of the parameters and test the actual call.
- draw_vk_info.isLayer = true;
+ SkMatrix44 mat4(mMatrix);
+ VkFunctorDrawParams params{
+ .width = mImageInfo.width(),
+ .height = mImageInfo.height(),
+ .is_layer = false, // TODO(boliu): Populate is_layer.
+ .color_space_ptr = mImageInfo.colorSpace(),
+ .clip_left = mClip.fLeft,
+ .clip_top = mClip.fTop,
+ .clip_right = mClip.fRight,
+ .clip_bottom = mClip.fBottom,
+ };
+ mat4.asColMajorf(&params.transform[0]);
+ params.secondary_command_buffer = vulkan_info.fSecondaryCommandBuffer;
+ params.color_attachment_index = vulkan_info.fColorAttachmentIndex;
+ params.compatible_render_pass = vulkan_info.fCompatibleRenderPass;
+ params.format = vulkan_info.fFormat;
- (*mFunctor)(DrawVkInfo::kModeComposite, &draw_vk_info);
+ mFunctorHandle->drawVk(params);
+
+ vulkan_info.fDrawBounds->offset.x = mClip.fLeft;
+ vulkan_info.fDrawBounds->offset.y = mClip.fTop;
+ vulkan_info.fDrawBounds->extent.width = mClip.fRight - mClip.fLeft;
+ vulkan_info.fDrawBounds->extent.height = mClip.fBottom - mClip.fTop;
}
VkFunctorDrawable::~VkFunctorDrawable() {
- if (auto lp = std::get_if<LegacyFunctor>(&mAnyFunctor)) {
- if (lp->listener) {
- lp->listener->onGlFunctorReleased(lp->functor);
- }
- }
}
void VkFunctorDrawable::onDraw(SkCanvas* /*canvas*/) {
@@ -67,16 +93,17 @@ void VkFunctorDrawable::onDraw(SkCanvas* /*canvas*/) {
}
std::unique_ptr<FunctorDrawable::GpuDrawHandler> VkFunctorDrawable::onSnapGpuDrawHandler(
- GrBackendApi backendApi, const SkMatrix& matrix) {
+ GrBackendApi backendApi, const SkMatrix& matrix, const SkIRect& clip,
+ const SkImageInfo& image_info) {
if (backendApi != GrBackendApi::kVulkan) {
return nullptr;
}
std::unique_ptr<VkFunctorDrawHandler> draw;
if (mAnyFunctor.index() == 0) {
- LOG_ALWAYS_FATAL("Not implemented");
- return nullptr;
+ return std::make_unique<VkFunctorDrawHandler>(std::get<0>(mAnyFunctor).handle, matrix, clip,
+ image_info);
} else {
- return std::make_unique<VkFunctorDrawHandler>(std::get<1>(mAnyFunctor).functor);
+ LOG_ALWAYS_FATAL("Not implemented");
}
}
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.h b/libs/hwui/pipeline/skia/VkFunctorDrawable.h
index d6fefc1fca06..1a53c8fd55db 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.h
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.h
@@ -32,15 +32,18 @@ namespace skiapipeline {
*/
class VkFunctorDrawHandler : public FunctorDrawable::GpuDrawHandler {
public:
- explicit VkFunctorDrawHandler(Functor* functor);
+ VkFunctorDrawHandler(sp<WebViewFunctor::Handle> functor_handle, const SkMatrix& matrix,
+ const SkIRect& clip, const SkImageInfo& image_info);
~VkFunctorDrawHandler() override;
void draw(const GrBackendDrawableInfo& info) override;
private:
typedef GpuDrawHandler INHERITED;
-
- Functor* mFunctor;
+ sp<WebViewFunctor::Handle> mFunctorHandle;
+ const SkMatrix mMatrix;
+ const SkIRect mClip;
+ const SkImageInfo mImageInfo;
};
/**
@@ -57,7 +60,8 @@ protected:
// SkDrawable functions:
void onDraw(SkCanvas* canvas) override;
std::unique_ptr<FunctorDrawable::GpuDrawHandler> onSnapGpuDrawHandler(
- GrBackendApi backendApi, const SkMatrix& matrix) override;
+ GrBackendApi backendApi, const SkMatrix& matrix, const SkIRect& clip,
+ const SkImageInfo& image_info) override;
};
} // namespace skiapipeline
diff --git a/libs/hwui/private/hwui/DrawVkInfo.h b/libs/hwui/private/hwui/DrawVkInfo.h
index fd824bd957fd..abc4dbf9fa1c 100644
--- a/libs/hwui/private/hwui/DrawVkInfo.h
+++ b/libs/hwui/private/hwui/DrawVkInfo.h
@@ -17,80 +17,61 @@
#ifndef ANDROID_HWUI_DRAW_VK_INFO_H
#define ANDROID_HWUI_DRAW_VK_INFO_H
+#include <SkColorSpace.h>
#include <vulkan/vulkan.h>
namespace android {
namespace uirenderer {
-/**
- * Structure used by VulkanRenderer::callDrawVKFunction() to pass and receive data from Vulkan
- * functors.
- */
-struct DrawVkInfo {
- // Input: current width/height of destination surface
- int width;
- int height;
-
- // Input: is the render target an FBO
- bool isLayer;
-
- // Input: current transform matrix, in OpenGL format
- float transform[16];
-
- // Input: WebView should do its main compositing draws into this. It cannot do anything that
- // would require stopping the render pass.
- VkCommandBuffer secondaryCommandBuffer;
-
- // Input: The main color attachment index where secondaryCommandBuffer will eventually be
- // submitted.
- uint32_t colorAttachmentIndex;
-
- // Input: A render pass which will be compatible to the one which the secondaryCommandBuffer
- // will be submitted into.
- VkRenderPass compatibleRenderPass;
-
- // Input: Format of the destination surface.
- VkFormat format;
-
- // Input: Color space
- const SkColorSpace* colorSpaceInfo;
-
- // Input: current clip rect
- int clipLeft;
- int clipTop;
- int clipRight;
- int clipBottom;
-
- /**
- * Values used as the "what" parameter of the functor.
- */
- enum Mode {
- // Called once at WebView start
- kModeInit,
- // Called when things need to be re-created
- kModeReInit,
- // Notifies the app that the composite functor will be called soon. This allows WebView to
- // begin work early.
- kModePreComposite,
- // Do the actual composite work
- kModeComposite,
- // This allows WebView to begin using the previously submitted objects in future work.
- kModePostComposite,
- // Invoked every time the UI thread pushes over a frame to the render thread and the owning
- // view has a dirty display list*. This is a signal to sync any data that needs to be
- // shared between the UI thread and the render thread. During this time the UI thread is
- // blocked.
- kModeSync
- };
-
- /**
- * Values used by Vulkan functors to tell the framework what to do next.
- */
- enum Status {
- // The functor is done
- kStatusDone = 0x0,
- };
-}; // struct DrawVkInfo
+struct VkFunctorInitParams {
+ VkInstance instance;
+ VkPhysicalDevice physical_device;
+ VkDevice device;
+ VkQueue queue;
+ uint32_t graphics_queue_index;
+ uint32_t instance_version;
+ const char* const* enabled_instance_extension_names;
+ uint32_t enabled_instance_extension_names_length;
+ const char* const* enabled_device_extension_names;
+ uint32_t enabled_device_extension_names_length;
+ const VkPhysicalDeviceFeatures2* device_features_2;
+};
+
+struct VkFunctorDrawParams {
+ // Input: current width/height of destination surface.
+ int width;
+ int height;
+
+ // Input: is the render target a FBO
+ bool is_layer;
+
+ // Input: current transform matrix
+ float transform[16];
+
+ // Input WebView should do its main compositing draws into this. It cannot do
+ // anything that would require stopping the render pass.
+ VkCommandBuffer secondary_command_buffer;
+
+ // Input: The main color attachment index where secondary_command_buffer will
+ // eventually be submitted.
+ uint32_t color_attachment_index;
+
+ // Input: A render pass which will be compatible to the one which the
+ // secondary_command_buffer will be submitted into.
+ VkRenderPass compatible_render_pass;
+
+ // Input: Format of the destination surface.
+ VkFormat format;
+
+ // Input: Color space.
+ const SkColorSpace* color_space_ptr;
+
+ // Input: current clip rect
+ int clip_left;
+ int clip_top;
+ int clip_right;
+ int clip_bottom;
+};
} // namespace uirenderer
} // namespace android
diff --git a/libs/hwui/private/hwui/WebViewFunctor.h b/libs/hwui/private/hwui/WebViewFunctor.h
index da3d06a4d60c..96da947ace08 100644
--- a/libs/hwui/private/hwui/WebViewFunctor.h
+++ b/libs/hwui/private/hwui/WebViewFunctor.h
@@ -19,6 +19,7 @@
#include <cutils/compiler.h>
#include <private/hwui/DrawGlInfo.h>
+#include <private/hwui/DrawVkInfo.h>
namespace android::uirenderer {
@@ -52,18 +53,12 @@ struct WebViewFunctorCallbacks {
// Called on RenderThread. initialize is guaranteed to happen before this call
void (*draw)(int functor, void* data, const DrawGlInfo& params);
} gles;
- // TODO: VK support. The current DrawVkInfo is monolithic and needs to be split up for
- // what params are valid on what callbacks
struct {
// Called either the first time the functor is used or the first time it's used after
// a call to onContextDestroyed.
- // void (*initialize)(int functor, const InitParams& params);
- // void (*frameStart)(int functor, /* todo: what params are actually needed for this to
- // be useful? Is this useful? */)
- // void (*draw)(int functor, const CompositeParams& params /* todo: rename - composite
- // almost always means something else, and we aren't compositing */);
- // void (*frameEnd)(int functor, const PostCompositeParams& params /* todo: same as
- // CompositeParams - rename */);
+ void (*initialize)(int functor, void* data, const VkFunctorInitParams& params);
+ void (*draw)(int functor, void* data, const VkFunctorDrawParams& params);
+ void (*postDraw)(int functor, void*);
} vk;
};
};
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 5272227509c8..1ef83fb26c14 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -47,6 +47,10 @@ class Readback;
class RenderState;
class TestUtils;
+namespace skiapipeline {
+class VkFunctorDrawHandler;
+}
+
namespace renderthread {
class CanvasContext;
@@ -124,6 +128,7 @@ private:
friend class DummyVsyncSource;
friend class android::uirenderer::TestUtils;
friend class android::uirenderer::WebViewFunctor;
+ friend class android::uirenderer::skiapipeline::VkFunctorDrawHandler;
RenderThread();
virtual ~RenderThread();
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index aa7a141f6da3..6c540f627a68 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -34,6 +34,23 @@ namespace android {
namespace uirenderer {
namespace renderthread {
+static void free_features_extensions_structs(const VkPhysicalDeviceFeatures2& features) {
+ // All Vulkan structs that could be part of the features chain will start with the
+ // structure type followed by the pNext pointer. We cast to the CommonVulkanHeader
+ // so we can get access to the pNext for the next struct.
+ struct CommonVulkanHeader {
+ VkStructureType sType;
+ void* pNext;
+ };
+
+ void* pNext = features.pNext;
+ while (pNext) {
+ void* current = pNext;
+ pNext = static_cast<CommonVulkanHeader*>(current)->pNext;
+ free(current);
+ }
+}
+
#define GET_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(VK_NULL_HANDLE, "vk" #F)
#define GET_INST_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(mInstance, "vk" #F)
#define GET_DEV_PROC(F) m##F = (PFN_vk##F)vkGetDeviceProcAddr(mDevice, "vk" #F)
@@ -66,6 +83,11 @@ void VulkanManager::destroy() {
mDevice = VK_NULL_HANDLE;
mPhysicalDevice = VK_NULL_HANDLE;
mInstance = VK_NULL_HANDLE;
+ mInstanceVersion = 0u;
+ mInstanceExtensions.clear();
+ mDeviceExtensions.clear();
+ free_features_extensions_structs(mPhysicalDeviceFeatures2);
+ mPhysicalDeviceFeatures2 = {};
}
bool VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFeatures2& features) {
@@ -81,7 +103,6 @@ bool VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe
VK_MAKE_VERSION(1, 1, 0), // apiVersion
};
- std::vector<const char*> instanceExtensions;
{
GET_PROC(EnumerateInstanceExtensionProperties);
@@ -99,7 +120,7 @@ bool VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe
bool hasKHRSurfaceExtension = false;
bool hasKHRAndroidSurfaceExtension = false;
for (uint32_t i = 0; i < extensionCount; ++i) {
- instanceExtensions.push_back(extensions[i].extensionName);
+ mInstanceExtensions.push_back(extensions[i].extensionName);
if (!strcmp(extensions[i].extensionName, VK_KHR_SURFACE_EXTENSION_NAME)) {
hasKHRSurfaceExtension = true;
}
@@ -120,8 +141,8 @@ bool VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe
&app_info, // pApplicationInfo
0, // enabledLayerNameCount
nullptr, // ppEnabledLayerNames
- (uint32_t) instanceExtensions.size(), // enabledExtensionNameCount
- instanceExtensions.data(), // ppEnabledExtensionNames
+ (uint32_t) mInstanceExtensions.size(), // enabledExtensionNameCount
+ mInstanceExtensions.data(), // ppEnabledExtensionNames
};
GET_PROC(CreateInstance);
@@ -201,7 +222,6 @@ bool VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe
// presentation with any native window. So just use the first one.
mPresentQueueIndex = 0;
- std::vector<const char*> deviceExtensions;
{
uint32_t extensionCount = 0;
err = mEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr, &extensionCount,
@@ -220,7 +240,7 @@ bool VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe
}
bool hasKHRSwapchainExtension = false;
for (uint32_t i = 0; i < extensionCount; ++i) {
- deviceExtensions.push_back(extensions[i].extensionName);
+ mDeviceExtensions.push_back(extensions[i].extensionName);
if (!strcmp(extensions[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
hasKHRSwapchainExtension = true;
}
@@ -237,8 +257,8 @@ bool VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe
}
return vkGetInstanceProcAddr(instance, proc_name);
};
- grExtensions.init(getProc, mInstance, mPhysicalDevice, instanceExtensions.size(),
- instanceExtensions.data(), deviceExtensions.size(), deviceExtensions.data());
+ grExtensions.init(getProc, mInstance, mPhysicalDevice, mInstanceExtensions.size(),
+ mInstanceExtensions.data(), mDeviceExtensions.size(), mDeviceExtensions.data());
if (!grExtensions.hasExtension(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, 1)) {
this->destroy();
@@ -308,8 +328,8 @@ bool VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe
queueInfo, // pQueueCreateInfos
0, // layerCount
nullptr, // ppEnabledLayerNames
- (uint32_t) deviceExtensions.size(), // extensionCount
- deviceExtensions.data(), // ppEnabledExtensionNames
+ (uint32_t) mDeviceExtensions.size(), // extensionCount
+ mDeviceExtensions.data(), // ppEnabledExtensionNames
nullptr, // ppEnabledFeatures
};
@@ -351,36 +371,17 @@ bool VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe
return true;
}
-static void free_features_extensions_structs(const VkPhysicalDeviceFeatures2& features) {
- // All Vulkan structs that could be part of the features chain will start with the
- // structure type followed by the pNext pointer. We cast to the CommonVulkanHeader
- // so we can get access to the pNext for the next struct.
- struct CommonVulkanHeader {
- VkStructureType sType;
- void* pNext;
- };
-
- void* pNext = features.pNext;
- while (pNext) {
- void* current = pNext;
- pNext = static_cast<CommonVulkanHeader*>(current)->pNext;
- free(current);
- }
-}
-
void VulkanManager::initialize() {
if (mDevice != VK_NULL_HANDLE) {
return;
}
GET_PROC(EnumerateInstanceVersion);
- uint32_t instanceVersion = 0;
- LOG_ALWAYS_FATAL_IF(mEnumerateInstanceVersion(&instanceVersion));
- LOG_ALWAYS_FATAL_IF(instanceVersion < VK_MAKE_VERSION(1, 1, 0));
+ LOG_ALWAYS_FATAL_IF(mEnumerateInstanceVersion(&mInstanceVersion));
+ LOG_ALWAYS_FATAL_IF(mInstanceVersion < VK_MAKE_VERSION(1, 1, 0));
GrVkExtensions extensions;
- VkPhysicalDeviceFeatures2 features;
- LOG_ALWAYS_FATAL_IF(!this->setupDevice(extensions, features));
+ LOG_ALWAYS_FATAL_IF(!this->setupDevice(extensions, mPhysicalDeviceFeatures2));
mGetDeviceQueue(mDevice, mGraphicsQueueIndex, 0, &mGraphicsQueue);
@@ -397,9 +398,9 @@ void VulkanManager::initialize() {
backendContext.fDevice = mDevice;
backendContext.fQueue = mGraphicsQueue;
backendContext.fGraphicsQueueIndex = mGraphicsQueueIndex;
- backendContext.fInstanceVersion = instanceVersion;
+ backendContext.fInstanceVersion = mInstanceVersion;
backendContext.fVkExtensions = &extensions;
- backendContext.fDeviceFeatures2 = &features;
+ backendContext.fDeviceFeatures2 = &mPhysicalDeviceFeatures2;
backendContext.fGetProc = std::move(getProc);
// create the command pool for the command buffers
@@ -433,13 +434,29 @@ void VulkanManager::initialize() {
LOG_ALWAYS_FATAL_IF(!grContext.get());
mRenderThread.setGrContext(grContext);
- free_features_extensions_structs(features);
-
if (Properties::enablePartialUpdates && Properties::useBufferAge) {
mSwapBehavior = SwapBehavior::BufferAge;
}
}
+VkFunctorInitParams VulkanManager::getVkFunctorInitParams() const {
+ return VkFunctorInitParams{
+ .instance = mInstance,
+ .physical_device = mPhysicalDevice,
+ .device = mDevice,
+ .queue = mGraphicsQueue,
+ .graphics_queue_index = mGraphicsQueueIndex,
+ .instance_version = mInstanceVersion,
+ .enabled_instance_extension_names = mInstanceExtensions.data(),
+ .enabled_instance_extension_names_length =
+ static_cast<uint32_t>(mInstanceExtensions.size()),
+ .enabled_device_extension_names = mDeviceExtensions.data(),
+ .enabled_device_extension_names_length =
+ static_cast<uint32_t>(mDeviceExtensions.size()),
+ .device_features_2 = &mPhysicalDeviceFeatures2,
+ };
+}
+
// Returns the next BackbufferInfo to use for the next draw. The function will make sure all
// previous uses have finished before returning.
VulkanSurface::BackbufferInfo* VulkanManager::getAvailableBackbuffer(VulkanSurface* surface) {
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 9eb942c9d6ee..105ee093a057 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -132,6 +132,9 @@ public:
// Creates a fence that is signaled, when all the pending Vulkan commands are flushed.
status_t createReleaseFence(sp<Fence>& nativeFence);
+ // Returned pointers are owned by VulkanManager.
+ VkFunctorInitParams getVkFunctorInitParams() const;
+
private:
friend class RenderThread;
@@ -234,6 +237,12 @@ private:
VkCommandBuffer mDummyCB = VK_NULL_HANDLE;
+ // Variables saved to populate VkFunctorInitParams.
+ uint32_t mInstanceVersion = 0u;
+ std::vector<const char*> mInstanceExtensions;
+ std::vector<const char*> mDeviceExtensions;
+ VkPhysicalDeviceFeatures2 mPhysicalDeviceFeatures2{};
+
enum class SwapBehavior {
Discard,
BufferAge,
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 793aa270e2fd..55160869ad0a 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -17,6 +17,7 @@
package android.media;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
@@ -816,7 +817,7 @@ public final class AudioFormat implements Parcelable {
*
* @return The audio frame size in bytes corresponding to the encoding and the channel mask.
*/
- public int getFrameSizeInBytes() {
+ public @IntRange(from = 1) int getFrameSizeInBytes() {
return mFrameSizeInBytes;
}
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index df96994b0c36..aa79c417922c 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -60,6 +60,7 @@ import java.net.URL;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
@@ -67,6 +68,7 @@ import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
@@ -399,8 +401,7 @@ public class MediaPlayer2 implements AutoCloseable
clearSourceInfos();
// Modular DRM clean up
- mOnDrmConfigHelper = null;
- synchronized (mDrmEventCbLock) {
+ synchronized (mDrmEventCallbackLock) {
mDrmEventCallbackRecords.clear();
}
@@ -775,7 +776,7 @@ public class MediaPlayer2 implements AutoCloseable
}
boolean hasError = false;
for (DataSourceDesc dsd : dsds) {
- if (dsd != null) {
+ if (dsd == null) {
hasError = true;
continue;
}
@@ -2889,7 +2890,7 @@ public class MediaPlayer2 implements AutoCloseable
}
private void sendDrmEvent(final DrmEventNotifier notifier) {
- synchronized (mDrmEventCbLock) {
+ synchronized (mDrmEventCallbackLock) {
try {
for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
cb.first.execute(() -> notifier.notify(cb.second));
@@ -2901,12 +2902,28 @@ public class MediaPlayer2 implements AutoCloseable
}
}
+ private <T> T sendDrmEventWait(final DrmEventNotifier<T> notifier)
+ throws InterruptedException, ExecutionException {
+ synchronized (mDrmEventCallbackLock) {
+ mDrmEventCallbackRecords.get(0);
+ for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
+ CompletableFuture<T> ret = new CompletableFuture<>();
+ cb.first.execute(() -> ret.complete(notifier.notifyWait(cb.second)));
+ return ret.get();
+ }
+ }
+ return null;
+ }
+
private interface EventNotifier {
void notify(EventCallback callback);
}
- private interface DrmEventNotifier {
- void notify(DrmEventCallback callback);
+ private interface DrmEventNotifier<T> {
+ default void notify(DrmEventCallback callback) { }
+ default T notifyWait(DrmEventCallback callback) {
+ return null;
+ }
}
/* Do not change these values without updating their counterparts
@@ -3351,73 +3368,209 @@ public class MediaPlayer2 implements AutoCloseable
// Modular DRM begin
/**
- * Interface definition of a callback to be invoked when the app
- * can do DRM configuration (get/set properties) before the session
- * is opened. This facilitates configuration of the properties, like
- * 'securityLevel', which has to be set after DRM scheme creation but
- * before the DRM session is opened.
+ * An immutable structure per {@link DataSourceDesc} with settings required to initiate a DRM
+ * protected playback session.
*
- * The only allowed DRM calls in this listener are
- * {@link MediaPlayer2#getDrmPropertyString(DataSourceDesc, String)}
- * and {@link MediaPlayer2#setDrmPropertyString(DataSourceDesc, String, String)}.
- * @hide
+ * @see DrmPreparationInfo.Builder
*/
- public interface OnDrmConfigHelper {
+ public static final class DrmPreparationInfo {
+
/**
- * Called to give the app the opportunity to configure DRM before the session is created
- *
- * @param mp the {@code MediaPlayer2} associated with this callback
- * @param dsd the DataSourceDesc of this data source
+ * Mutable builder to create a {@link MediaPlayer2.DrmPreparationInfo} object.
*/
- public void onDrmConfig(MediaPlayer2 mp, DataSourceDesc dsd);
- }
+ public static final class Builder {
+
+ private UUID mUUID;
+ private byte[] mKeySetId;
+ private byte[] mInitData;
+ private String mMimeType;
+ private int mKeyType;
+ private Map<String, String> mOptionalParameters;
+
+ /**
+ * Set UUID of the crypto scheme selected to decrypt content. An UUID can be retrieved from
+ * the source listening to {@link MediaPlayer2.DrmEventCallback#onDrmInfo}.
+ *
+ * @param uuid of selected crypto scheme
+ * @return this
+ */
+ public Builder setUuid(@NonNull UUID uuid) {
+ this.mUUID = uuid;
+ return this;
+ }
- /**
- * Register a callback to be invoked for configuration of the DRM object before
- * the session is created.
- * The callback will be invoked synchronously during the execution
- * of {@link #prepareDrm}.
- *
- * @param listener the callback that will be run
- * @hide
- */
- // This is a synchronous call.
- public void setOnDrmConfigHelper(OnDrmConfigHelper listener) {
- mOnDrmConfigHelper = listener;
- }
+ /**
+ * Set identifier of a persisted offline key obtained from
+ * {@link MediaPlayer2.DrmEventCallback#onDrmPrepared(MediaPlayer2, DataSourceDesc, int, byte[])}.
+ *
+ * A {@code keySetId} can be used to restore persisted offline keys into a new playback
+ * session of a DRM protected data source. When {@code keySetId} is set, {@code initData},
+ * {@code mimeType}, {@code keyType}, {@code optionalParameters} are ignored.
+ *
+ * @param keySetId identifier of a persisted offline key
+ * @return this
+ */
+ public Builder setKeySetId(@Nullable byte[] keySetId) {
+ this.mKeySetId = keySetId;
+ return this;
+ }
+
+ /**
+ * Set container-specific DRM initialization data. Its meaning is interpreted based on
+ * {@code mimeType}. For example, it could contain the content ID, key ID or other data
+ * obtained from the content metadata that is required to generate a
+ * {@link MediaDrm.KeyRequest}.
+ *
+ * @param initData container-specific DRM initialization data
+ * @return this
+ */
+ public Builder setInitData(@Nullable byte[] initData) {
+ this.mInitData = initData;
+ return this;
+ }
+
+ /**
+ * Set mime type of the content
+ *
+ * @param mimeType mime type to the content
+ * @return this
+ */
+ public Builder setMimeType(@Nullable String mimeType) {
+ this.mMimeType = mimeType;
+ return this;
+ }
+
+ /**
+ * Set type of the key request. The request may be to acquire keys
+ * for streaming, {@link MediaDrm#KEY_TYPE_STREAMING}, or for offline content,
+ * {@link MediaDrm#KEY_TYPE_OFFLINE}. Releasing previously acquired keys
+ * ({@link MediaDrm#KEY_TYPE_RELEASE}) is not allowed.
+ *
+ * @param keyType type of the key request
+ * @return this
+ */
+ public Builder setKeyType(@MediaPlayer2.MediaDrmKeyType int keyType) {
+ this.mKeyType = keyType;
+ return this;
+ }
+
+ /**
+ * Set optional parameters to be included in a {@link MediaDrm.KeyRequest} message sent to
+ * the license server.
+ *
+ * @param optionalParameters optional parameters to be included in a key request
+ * @return this
+ */
+ public Builder setOptionalParameters(
+ @Nullable Map<String, String> optionalParameters) {
+ this.mOptionalParameters = optionalParameters;
+ return this;
+ }
+
+ /**
+ * @return an immutable {@link MediaPlayer2.DrmPreparationInfo} representing the settings of this builder
+ */
+ public MediaPlayer2.DrmPreparationInfo build() {
+ return new MediaPlayer2.DrmPreparationInfo(mUUID, mKeySetId, mInitData, mMimeType, mKeyType,
+ mOptionalParameters);
+ }
+
+ }
+
+ private final UUID mUUID;
+ private final byte[] mKeySetId;
+ private final byte[] mInitData;
+ private final String mMimeType;
+ private final int mKeyType;
+ private final Map<String, String> mOptionalParameters;
- private OnDrmConfigHelper mOnDrmConfigHelper;
+ private DrmPreparationInfo(UUID mUUID, byte[] mKeySetId, byte[] mInitData, String mMimeType,
+ int mKeyType, Map<String, String> optionalParameters) {
+ this.mUUID = mUUID;
+ this.mKeySetId = mKeySetId;
+ this.mInitData = mInitData;
+ this.mMimeType = mMimeType;
+ this.mKeyType = mKeyType;
+ this.mOptionalParameters = optionalParameters;
+ }
+
+ }
/**
* Interface definition for callbacks to be invoked when the player has the corresponding
* DRM events.
- * @hide
*/
public static class DrmEventCallback {
/**
- * Called to indicate DRM info is available
+ * Called to indicate DRM info is available. Return a {@link DrmPreparationInfo} object that
+ * bundles DRM initialization parameters.
*
* @param mp the {@code MediaPlayer2} associated with this callback
- * @param dsd the DataSourceDesc of this data source
- * @param drmInfo DRM info of the source including PSSH, and subset
- * of crypto schemes supported by this device
+ * @param dsd the {@link DataSourceDesc} of this data source
+ * @param drmInfo DRM info of the source including PSSH, and subset of crypto schemes
+ * supported by this device
+ * @return a {@link DrmPreparationInfo} object to initialize DRM playback, or null to skip
+ * DRM initialization
*/
- public void onDrmInfo(MediaPlayer2 mp, DataSourceDesc dsd, DrmInfo drmInfo) { }
+ public DrmPreparationInfo onDrmInfo(MediaPlayer2 mp, DataSourceDesc dsd, DrmInfo drmInfo) {
+ return null;
+ }
/**
- * Called to notify the client that {@link MediaPlayer2#prepareDrm(DataSourceDesc, UUID)}
- * is finished and ready for key request/response.
+ * Called to notify the client that {@code mp} is ready to decrypt DRM protected data source
+ * {@code dsd}
*
* @param mp the {@code MediaPlayer2} associated with this callback
- * @param dsd the DataSourceDesc of this data source
+ * @param dsd the {@link DataSourceDesc} of this data source
* @param status the result of DRM preparation.
+ * @param keySetId optional identifier that can be used to restore DRM playback initiated
+ * with a {@link MediaDrm#KEY_TYPE_OFFLINE} key request.
+ *
+ * @see DrmPreparationInfo.Builder#setKeySetId(byte[])
+ */
+ public void onDrmPrepared(@NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+ @PrepareDrmStatusCode int status, @Nullable byte[] keySetId) { }
+
+ /**
+ * Called to give the app the opportunity to configure DRM before the session is created.
+ *
+ * This facilitates configuration of the properties, like 'securityLevel', which
+ * has to be set after DRM scheme creation but before the DRM session is opened.
+ *
+ * The only allowed DRM calls in this listener are
+ * {@link MediaDrm#getPropertyString(String)},
+ * {@link MediaDrm#getPropertyByteArray(String)},
+ * {@link MediaDrm#setPropertyString(String, String)},
+ * {@link MediaDrm#setPropertyByteArray(String, byte[])},
+ * {@link MediaDrm#setOnExpirationUpdateListener},
+ * and {@link MediaDrm#setOnKeyStatusChangeListener}.
+ *
+ * @param mp the {@code MediaPlayer2} associated with this callback
+ * @param dsd the {@link DataSourceDesc} of this data source
+ * @param drm handle to get/set DRM properties and listeners for this data source
*/
- public void onDrmPrepared(
- MediaPlayer2 mp, DataSourceDesc dsd, @PrepareDrmStatusCode int status) { }
+ public void onDrmConfig(@NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+ @NonNull MediaDrm drm) { }
+
+ /**
+ * Called to indicate the DRM session for {@code dsd} is ready for key request/response
+ *
+ * @param mp the {@code MediaPlayer2} associated with this callback
+ * @param dsd the {@link DataSourceDesc} of this data source
+ * @param request a {@link MediaDrm.KeyRequest} prepared using the
+ * {@link DrmPreparationInfo} returned from
+ * {@link #onDrmInfo(MediaPlayer2, DataSourceDesc, DrmInfo)}
+ * @return the response to {@code request} (from license server)
+ */
+ public byte[] onDrmKeyRequest(@NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
+ @NonNull MediaDrm.KeyRequest request) {
+ return null;
+ }
+
}
- private final Object mDrmEventCbLock = new Object();
- private ArrayList<Pair<Executor, DrmEventCallback>> mDrmEventCallbackRecords =
+ private final Object mDrmEventCallbackLock = new Object();
+ private List<Pair<Executor, DrmEventCallback>> mDrmEventCallbackRecords =
new ArrayList<Pair<Executor, DrmEventCallback>>();
/**
@@ -3425,10 +3578,9 @@ public class MediaPlayer2 implements AutoCloseable
*
* @param eventCallback the callback that will be run
* @param executor the executor through which the callback should be invoked
- * @hide
*/
// This is a synchronous call.
- public void registerDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
+ public void setDrmEventCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull DrmEventCallback eventCallback) {
if (eventCallback == null) {
throw new IllegalArgumentException("Illegal null EventCallback");
@@ -3437,8 +3589,9 @@ public class MediaPlayer2 implements AutoCloseable
throw new IllegalArgumentException(
"Illegal null Executor for the EventCallback");
}
- synchronized (mDrmEventCbLock) {
- mDrmEventCallbackRecords.add(new Pair(executor, eventCallback));
+ synchronized (mDrmEventCallbackLock) {
+ mDrmEventCallbackRecords = Collections.singletonList(
+ new Pair<Executor, DrmEventCallback>(executor, eventCallback));
}
}
@@ -3450,7 +3603,7 @@ public class MediaPlayer2 implements AutoCloseable
*/
// This is a synchronous call.
public void unregisterDrmEventCallback(DrmEventCallback eventCallback) {
- synchronized (mDrmEventCbLock) {
+ synchronized (mDrmEventCallbackLock) {
for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
if (cb.second == eventCallback) {
mDrmEventCallbackRecords.remove(cb);
@@ -3564,7 +3717,7 @@ public class MediaPlayer2 implements AutoCloseable
/**
* Prepares the DRM for the given data source
* <p>
- * If {@link OnDrmConfigHelper} is registered, it will be called during
+ * If {@link DrmEventCallback} is registered, it will be called during
* preparation to allow configuration of the DRM properties before opening the
* DRM session. It should be used only for a series of
* {@link #getDrmPropertyString(DataSourceDesc, String)} and
@@ -3587,8 +3740,7 @@ public class MediaPlayer2 implements AutoCloseable
* @param dsd The DRM protected data source
*
* @param uuid The UUID of the crypto scheme. If not known beforehand, it can be retrieved
- * from the source through {@link #getDrmInfo(DataSourceDesc)} or registering a
- * {@link DrmEventCallback#onDrmInfo}.
+ * from the source listening to {@link DrmEventCallback#onDrmInfo}.
*
* @return a token which can be used to cancel the operation later with {@link #cancelCommand}.
* @hide
@@ -3661,8 +3813,8 @@ public class MediaPlayer2 implements AutoCloseable
sendDrmEvent(new DrmEventNotifier() {
@Override
public void notify(DrmEventCallback callback) {
- callback.onDrmPrepared(
- MediaPlayer2.this, dsd, prepareDrmStatus);
+ callback.onDrmPrepared(MediaPlayer2.this, dsd, prepareDrmStatus,
+ /* TODO: keySetId */ null);
}
});
@@ -3876,7 +4028,6 @@ public class MediaPlayer2 implements AutoCloseable
/**
* Encapsulates the DRM properties of the source.
- * @hide
*/
public static final class DrmInfo {
private Map<UUID, byte[]> mMapPssh;
@@ -4013,10 +4164,8 @@ public class MediaPlayer2 implements AutoCloseable
}; // DrmInfo
/**
- * Thrown when a DRM method is called before preparing a DRM scheme through
- * {@link MediaPlayer2#prepareDrm(DataSourceDesc, UUID)}.
+ * Thrown when a DRM method is called when there is no active DRM session.
* Extends MediaDrm.MediaDrmException
- * @hide
*/
public static final class NoDrmSchemeException extends MediaDrmException {
public NoDrmSchemeException(String detailMessage) {
@@ -4291,9 +4440,9 @@ public class MediaPlayer2 implements AutoCloseable
}
void prepare(UUID uuid) throws UnsupportedSchemeException,
- ResourceBusyException, NotProvisionedException {
- final OnDrmConfigHelper onDrmConfigHelper = mOnDrmConfigHelper;
- Log.v(TAG, "prepareDrm: uuid: " + uuid + " mOnDrmConfigHelper: " + onDrmConfigHelper);
+ ResourceBusyException, NotProvisionedException, InterruptedException,
+ ExecutionException {
+ Log.v(TAG, "prepareDrm: uuid: " + uuid);
synchronized (this) {
if (mActiveDrmUUID != null) {
@@ -4334,9 +4483,13 @@ public class MediaPlayer2 implements AutoCloseable
} // synchronized
// call the callback outside the lock
- if (onDrmConfigHelper != null) {
- onDrmConfigHelper.onDrmConfig(MediaPlayer2.this, mDSD);
- }
+ sendDrmEventWait(new DrmEventNotifier<Void>() {
+ @Override
+ public Void notifyWait(DrmEventCallback callback) {
+ callback.onDrmConfig(MediaPlayer2.this, mDSD, mDrmObj);
+ return null;
+ }
+ });
synchronized (this) {
mDrmConfigAllowed = false;
@@ -4506,7 +4659,7 @@ public class MediaPlayer2 implements AutoCloseable
@Override
public void notify(DrmEventCallback callback) {
callback.onDrmPrepared(
- MediaPlayer2.this, mDSD, finalStatus);
+ MediaPlayer2.this, mDSD, finalStatus, /* TODO: keySetId */ null);
}
});
diff --git a/native/webview/plat_support/draw_fn.h b/native/webview/plat_support/draw_fn.h
index bb2ee9b5da04..0490e650a7a4 100644
--- a/native/webview/plat_support/draw_fn.h
+++ b/native/webview/plat_support/draw_fn.h
@@ -74,7 +74,10 @@ struct AwDrawFn_InitVkParams {
VkQueue queue;
uint32_t graphics_queue_index;
uint32_t instance_version;
- const char* const* enabled_extension_names;
+ const char* const* enabled_instance_extension_names;
+ uint32_t enabled_instance_extension_names_length;
+ const char* const* enabled_device_extension_names;
+ uint32_t enabled_device_extension_names_length;
// Only one of device_features and device_features_2 should be non-null.
// If both are null then no features are enabled.
VkPhysicalDeviceFeatures* device_features;
@@ -128,15 +131,13 @@ struct AwDrawFn_DrawVkParams {
struct AwDrawFn_PostDrawVkParams {
int version;
-
- // Input: Fence for the composite command buffer to signal it has finished its
- // work on the GPU.
- int fd;
};
// Called on render thread while UI thread is blocked. Called for both GL and
// VK.
-typedef void AwDrawFn_OnSync(int functor, void* data, AwDrawFn_OnSyncParams* params);
+typedef void AwDrawFn_OnSync(int functor,
+ void* data,
+ AwDrawFn_OnSyncParams* params);
// Called on render thread when either the context is destroyed _or_ when the
// functor's last reference goes away. Will always be called with an active
@@ -150,17 +151,24 @@ typedef void AwDrawFn_OnContextDestroyed(int functor, void* data);
typedef void AwDrawFn_OnDestroyed(int functor, void* data);
// Only called for GL.
-typedef void AwDrawFn_DrawGL(int functor, void* data, AwDrawFn_DrawGLParams* params);
+typedef void AwDrawFn_DrawGL(int functor,
+ void* data,
+ AwDrawFn_DrawGLParams* params);
// Initialize vulkan state. Needs to be called again after any
// OnContextDestroyed. Only called for Vulkan.
-typedef void AwDrawFn_InitVk(int functor, void* data, AwDrawFn_InitVkParams* params);
+typedef void AwDrawFn_InitVk(int functor,
+ void* data,
+ AwDrawFn_InitVkParams* params);
// Only called for Vulkan.
-typedef void AwDrawFn_DrawVk(int functor, void* data, AwDrawFn_DrawVkParams* params);
+typedef void AwDrawFn_DrawVk(int functor,
+ void* data,
+ AwDrawFn_DrawVkParams* params);
// Only called for Vulkan.
-typedef void AwDrawFn_PostDrawVk(int functor, void* data,
+typedef void AwDrawFn_PostDrawVk(int functor,
+ void* data,
AwDrawFn_PostDrawVkParams* params);
struct AwDrawFnFunctorCallbacks {
@@ -183,7 +191,8 @@ enum AwDrawFnRenderMode {
typedef AwDrawFnRenderMode AwDrawFn_QueryRenderMode(void);
// Create a functor. |functor_callbacks| should be valid until OnDestroyed.
-typedef int AwDrawFn_CreateFunctor(void* data, AwDrawFnFunctorCallbacks* functor_callbacks);
+typedef int AwDrawFn_CreateFunctor(void* data,
+ AwDrawFnFunctorCallbacks* functor_callbacks);
// May be called on any thread to signal that the functor should be destroyed.
// The functor will receive an onDestroyed when the last usage of it is
diff --git a/native/webview/plat_support/draw_functor.cpp b/native/webview/plat_support/draw_functor.cpp
index 6c1ceaba4d46..b97bbc311624 100644
--- a/native/webview/plat_support/draw_functor.cpp
+++ b/native/webview/plat_support/draw_functor.cpp
@@ -74,6 +74,79 @@ void draw_gl(int functor, void* data,
support->callbacks.draw_gl(functor, support->data, &params);
}
+void initializeVk(int functor, void* data,
+ const uirenderer::VkFunctorInitParams& init_vk_params) {
+ SupportData* support = static_cast<SupportData*>(data);
+ VkPhysicalDeviceFeatures2 device_features_2;
+ if (init_vk_params.device_features_2)
+ device_features_2 = *init_vk_params.device_features_2;
+
+ AwDrawFn_InitVkParams params{
+ .version = kAwDrawFnVersion,
+ .instance = init_vk_params.instance,
+ .physical_device = init_vk_params.physical_device,
+ .device = init_vk_params.device,
+ .queue = init_vk_params.queue,
+ .graphics_queue_index = init_vk_params.graphics_queue_index,
+ .instance_version = init_vk_params.instance_version,
+ .enabled_instance_extension_names =
+ init_vk_params.enabled_instance_extension_names,
+ .enabled_instance_extension_names_length =
+ init_vk_params.enabled_instance_extension_names_length,
+ .enabled_device_extension_names =
+ init_vk_params.enabled_device_extension_names,
+ .enabled_device_extension_names_length =
+ init_vk_params.enabled_device_extension_names_length,
+ .device_features = nullptr,
+ .device_features_2 =
+ init_vk_params.device_features_2 ? &device_features_2 : nullptr,
+ };
+ support->callbacks.init_vk(functor, support->data, &params);
+}
+
+void drawVk(int functor, void* data, const uirenderer::VkFunctorDrawParams& draw_vk_params) {
+ SupportData* support = static_cast<SupportData*>(data);
+ float gabcdef[7];
+ draw_vk_params.color_space_ptr->transferFn(gabcdef);
+ AwDrawFn_DrawVkParams params{
+ .version = kAwDrawFnVersion,
+ .width = draw_vk_params.width,
+ .height = draw_vk_params.height,
+ .is_layer = draw_vk_params.is_layer,
+ .secondary_command_buffer = draw_vk_params.secondary_command_buffer,
+ .color_attachment_index = draw_vk_params.color_attachment_index,
+ .compatible_render_pass = draw_vk_params.compatible_render_pass,
+ .format = draw_vk_params.format,
+ .transfer_function_g = gabcdef[0],
+ .transfer_function_a = gabcdef[1],
+ .transfer_function_b = gabcdef[2],
+ .transfer_function_c = gabcdef[3],
+ .transfer_function_d = gabcdef[4],
+ .transfer_function_e = gabcdef[5],
+ .transfer_function_f = gabcdef[6],
+ .clip_left = draw_vk_params.clip_left,
+ .clip_top = draw_vk_params.clip_top,
+ .clip_right = draw_vk_params.clip_right,
+ .clip_bottom = draw_vk_params.clip_bottom,
+ };
+ COMPILE_ASSERT(sizeof(params.color_space_toXYZD50) == sizeof(skcms_Matrix3x3),
+ gamut_transform_size_mismatch);
+ draw_vk_params.color_space_ptr->toXYZD50(
+ reinterpret_cast<skcms_Matrix3x3*>(&params.color_space_toXYZD50));
+ COMPILE_ASSERT(NELEM(params.transform) == NELEM(draw_vk_params.transform),
+ mismatched_transform_matrix_sizes);
+ for (int i = 0; i < NELEM(params.transform); ++i) {
+ params.transform[i] = draw_vk_params.transform[i];
+ }
+ support->callbacks.draw_vk(functor, support->data, &params);
+}
+
+void postDrawVk(int functor, void* data) {
+ SupportData* support = static_cast<SupportData*>(data);
+ AwDrawFn_PostDrawVkParams params{.version = kAwDrawFnVersion};
+ support->callbacks.post_draw_vk(functor, support->data, &params);
+}
+
int CreateFunctor(void* data, AwDrawFnFunctorCallbacks* functor_callbacks) {
static bool callbacks_initialized = false;
static uirenderer::WebViewFunctorCallbacks webview_functor_callbacks = {
@@ -82,9 +155,19 @@ int CreateFunctor(void* data, AwDrawFnFunctorCallbacks* functor_callbacks) {
.onDestroyed = &onDestroyed,
};
if (!callbacks_initialized) {
- // Under uirenderer::RenderMode::Vulkan, whether gles or vk union should
- // be populated should match whether the vk-gl interop is used.
- webview_functor_callbacks.gles.draw = &draw_gl;
+ switch (uirenderer::WebViewFunctor_queryPlatformRenderMode()) {
+ case uirenderer::RenderMode::OpenGL_ES:
+ webview_functor_callbacks.gles.draw = &draw_gl;
+ break;
+ case uirenderer::RenderMode::Vulkan:
+ webview_functor_callbacks.vk.initialize = &initializeVk;
+ webview_functor_callbacks.vk.draw = &drawVk;
+ webview_functor_callbacks.vk.postDraw = &postDrawVk;
+ // TODO(boliu): Remove this once SkiaRecordingCanvas::drawWebViewFunctor
+ // no longer uses GL interop.
+ webview_functor_callbacks.gles.draw = &draw_gl;
+ break;
+ }
callbacks_initialized = true;
}
SupportData* support = new SupportData{
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index a29cf8449e51..9e89b890d583 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -103,6 +103,8 @@
<string name="ssid_by_passpoint_provider"><xliff:g id="ssid" example="Cafe Wifi">%1$s</xliff:g> by <xliff:g id="passpointProvider" example="Passpoint Provider">%2$s</xliff:g></string>
<!-- Status message of Wi-Fi when network has matching passpoint credentials. [CHAR LIMIT=NONE] -->
<string name="available_via_passpoint">Available via %1$s</string>
+ <!-- Status message of OSU Provider network when not connected. [CHAR LIMIT=NONE] -->
+ <string name="tap_to_set_up">Tap to set up</string>
<!-- Package name for Settings app-->
<string name="settings_package" translatable="false">com.android.settings</string>
<!-- Package name for Certinstaller app-->
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 1ae1d56aacc8..a97931a946bf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -926,6 +926,8 @@ public class AccessPoint implements Comparable<AccessPoint> {
} else if (mIsCarrierAp) {
summary.append(String.format(mContext.getString(
R.string.available_via_carrier), mCarrierName));
+ } else if (isOsuProvider()) {
+ summary.append(mContext.getString(R.string.tap_to_set_up));
} else if (!isReachable()) { // Wifi out of range
summary.append(mContext.getString(R.string.wifi_not_in_range));
} else { // In range, not disabled.
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
index 523720d54eec..1a684a0ffb8f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstanceManager.java
@@ -323,7 +323,7 @@ public class PluginInstanceManager<T extends Plugin> {
return null;
}
// Create our own ClassLoader so we can use our own code as the parent.
- ClassLoader classLoader = mManager.getClassLoader(info.sourceDir, info.packageName);
+ ClassLoader classLoader = mManager.getClassLoader(info);
Context pluginContext = new PluginContextWrapper(
mContext.createApplicationContext(info, 0), classLoader);
Class<?> pluginClass = Class.forName(cls, true, classLoader);
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
index da143f9bcbe3..7139708b65b9 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
@@ -14,6 +14,7 @@
package com.android.systemui.shared.plugins;
+import android.app.LoadedApk;
import android.app.Notification;
import android.app.Notification.Action;
import android.app.NotificationManager;
@@ -44,15 +45,17 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.annotations.ProvidesInterface;
-import com.android.systemui.shared.plugins.PluginInstanceManager.PluginContextWrapper;
import com.android.systemui.shared.plugins.PluginInstanceManager.PluginInfo;
import dalvik.system.PathClassLoader;
+import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.Thread.UncaughtExceptionHandler;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Map;
/**
* @see Plugin
@@ -117,6 +120,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
return mPluginEnabler;
}
+ // TODO(mankoff): This appears to be only called from tests. Remove?
public <T extends Plugin> T getOneShotPlugin(Class<T> cls) {
ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class);
if (info == null) {
@@ -282,17 +286,25 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
}
}
- public ClassLoader getClassLoader(String sourceDir, String pkg) {
- if (!isDebuggable && !mWhitelistedPlugins.contains(pkg)) {
- Log.w(TAG, "Cannot get class loader for non-whitelisted plugin. Src:" + sourceDir +
- ", pkg: " + pkg);
+ /** Returns class loader specific for the given plugin. */
+ public ClassLoader getClassLoader(ApplicationInfo appInfo) {
+ if (!isDebuggable && !mWhitelistedPlugins.contains(appInfo.packageName)) {
+ Log.w(TAG, "Cannot get class loader for non-whitelisted plugin. Src:"
+ + appInfo.sourceDir + ", pkg: " + appInfo.packageName);
return null;
}
- if (mClassLoaders.containsKey(pkg)) {
- return mClassLoaders.get(pkg);
+ if (mClassLoaders.containsKey(appInfo.packageName)) {
+ return mClassLoaders.get(appInfo.packageName);
}
- ClassLoader classLoader = new PathClassLoader(sourceDir, getParentClassLoader());
- mClassLoaders.put(pkg, classLoader);
+
+ List<String> zipPaths = new ArrayList<>();
+ List<String> libPaths = new ArrayList<>();
+ LoadedApk.makePaths(null, true, appInfo, zipPaths, libPaths);
+ ClassLoader classLoader = new PathClassLoader(
+ TextUtils.join(File.pathSeparator, zipPaths),
+ TextUtils.join(File.pathSeparator, libPaths),
+ getParentClassLoader());
+ mClassLoaders.put(appInfo.packageName, classLoader);
return classLoader;
}
@@ -309,11 +321,6 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
return mParentClassLoader;
}
- public Context getContext(ApplicationInfo info, String pkg) throws NameNotFoundException {
- ClassLoader classLoader = getClassLoader(info.sourceDir, pkg);
- return new PluginContextWrapper(mContext.createApplicationContext(info, 0), classLoader);
- }
-
public <T> boolean dependsOn(Plugin p, Class<T> cls) {
for (int i = 0; i < mPluginMap.size(); i++) {
if (mPluginMap.valueAt(i).dependsOn(p, cls)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 9422101c76dd..f79ad71a114f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -541,7 +541,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
@VisibleForTesting
void doUpdateMobileControllers() {
- List<SubscriptionInfo> subscriptions = mSubscriptionManager.getActiveSubscriptionInfoList();
+ List<SubscriptionInfo> subscriptions = mSubscriptionManager
+ .getActiveSubscriptionInfoList(true);
if (subscriptions == null) {
subscriptions = Collections.emptyList();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java
index 458377017fb9..3415c72230e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceManagerTest.java
@@ -91,7 +91,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
mMockPm = mock(PackageManager.class);
mMockListener = mock(PluginListener.class);
mMockManager = mock(PluginManagerImpl.class);
- when(mMockManager.getClassLoader(any(), any())).thenReturn(getClass().getClassLoader());
+ when(mMockManager.getClassLoader(any())).thenReturn(getClass().getClassLoader());
mMockEnabler = mock(PluginEnabler.class);
when(mMockManager.getPluginEnabler()).thenReturn(mMockEnabler);
mMockVersionInfo = mock(VersionInfo.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
index 76e68f1df724..536c043bd7ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginManagerTest.java
@@ -25,6 +25,7 @@ import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.test.suitebuilder.annotation.SmallTest;
@@ -135,9 +136,13 @@ public class PluginManagerTest extends SysuiTestCase {
});
resetExceptionHandler();
+ String sourceDir = "myPlugin";
+ ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.sourceDir = sourceDir;
+ applicationInfo.packageName = WHITELISTED_PACKAGE;
mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
- assertNull(mPluginManager.getOneShotPlugin("myPlugin", TestPlugin.class));
- assertNull(mPluginManager.getClassLoader("myPlugin", WHITELISTED_PACKAGE));
+ assertNull(mPluginManager.getOneShotPlugin(sourceDir, TestPlugin.class));
+ assertNull(mPluginManager.getClassLoader(applicationInfo));
}
@Test
@@ -152,9 +157,16 @@ public class PluginManagerTest extends SysuiTestCase {
});
resetExceptionHandler();
+ String sourceDir = "myPlugin";
+ ApplicationInfo whiteListedApplicationInfo = new ApplicationInfo();
+ whiteListedApplicationInfo.sourceDir = sourceDir;
+ whiteListedApplicationInfo.packageName = WHITELISTED_PACKAGE;
+ ApplicationInfo invalidApplicationInfo = new ApplicationInfo();
+ invalidApplicationInfo.sourceDir = sourceDir;
+ invalidApplicationInfo.packageName = "com.android.invalidpackage";
mPluginManager.addPluginListener("myAction", mMockListener, TestPlugin.class);
- assertNotNull(mPluginManager.getClassLoader("myPlugin", WHITELISTED_PACKAGE));
- assertNull(mPluginManager.getClassLoader("myPlugin", "com.android.invalidpackage"));
+ assertNotNull(mPluginManager.getClassLoader(whiteListedApplicationInfo));
+ assertNull(mPluginManager.getClassLoader(invalidApplicationInfo));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index fdbf09083a4e..c1f88855ac24 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -182,6 +182,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
subs.add(subscription);
}
when(mMockSm.getActiveSubscriptionInfoList()).thenReturn(subs);
+ when(mMockSm.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(subs);
mNetworkController.doUpdateMobileControllers();
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 869d564b4329..312b83c56dea 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -1041,12 +1041,13 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public void onSetProperties(ProviderProperties properties) {
- // move calls coming from below LMS onto a different thread to avoid deadlock
- runInternal(() -> {
- synchronized (mLock) {
- mProperties = properties;
- }
- });
+ // because this does not invoke any other methods which might result in calling back
+ // into the location provider, it is safe to run this on the calling thread. it is also
+ // currently necessary to run this on the calling thread to ensure that property changes
+ // are publicly visibly immediately, ie for mock providers which are created.
+ synchronized (mLock) {
+ mProperties = properties;
+ }
}
@GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 2340b77c4a3c..cb3f91b7b6bb 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -792,6 +792,16 @@ public final class DisplayManagerService extends SystemService {
}
}
+ private void setVirtualDisplayStateInternal(IBinder appToken, boolean isOn) {
+ synchronized (mSyncRoot) {
+ if (mVirtualDisplayAdapter == null) {
+ return;
+ }
+
+ mVirtualDisplayAdapter.setVirtualDisplayStateLocked(appToken, isOn);
+ }
+ }
+
private void registerDefaultDisplayAdapters() {
// Register default display adapters.
synchronized (mSyncRoot) {
@@ -1930,6 +1940,16 @@ public final class DisplayManagerService extends SystemService {
}
@Override // Binder call
+ public void setVirtualDisplayState(IVirtualDisplayCallback callback, boolean isOn) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ setVirtualDisplayStateInternal(callback.asBinder(), isOn);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index 5aa585fcad75..1ca8dd3af4e2 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -147,6 +147,13 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
return device;
}
+ void setVirtualDisplayStateLocked(IBinder appToken, boolean isOn) {
+ VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
+ if (device != null) {
+ device.setDisplayState(isOn);
+ }
+ }
+
/**
* Returns the next unique index for the uniqueIdPrefix
*/
@@ -206,6 +213,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
private int mPendingChanges;
private int mUniqueIndex;
private Display.Mode mMode;
+ private boolean mIsDisplayOn;
public VirtualDisplayDevice(IBinder displayToken, IBinder appToken,
int ownerUid, String ownerPackageName,
@@ -226,6 +234,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
mDisplayState = Display.STATE_UNKNOWN;
mPendingChanges |= PENDING_SURFACE_CHANGE;
mUniqueIndex = uniqueIndex;
+ mIsDisplayOn = surface != null;
}
@Override
@@ -304,6 +313,14 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
}
}
+ void setDisplayState(boolean isOn) {
+ if (mIsDisplayOn != isOn) {
+ mIsDisplayOn = isOn;
+ mInfo = null;
+ sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
+ }
+ }
+
public void stopLocked() {
setSurfaceLocked(null);
mStopped = true;
@@ -375,7 +392,9 @@ public class VirtualDisplayAdapter extends DisplayAdapter {
mInfo.type = Display.TYPE_VIRTUAL;
mInfo.touch = ((mFlags & VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH) == 0) ?
DisplayDeviceInfo.TOUCH_NONE : DisplayDeviceInfo.TOUCH_VIRTUAL;
- mInfo.state = mSurface != null ? Display.STATE_ON : Display.STATE_OFF;
+
+ mInfo.state = mIsDisplayOn ? Display.STATE_ON : Display.STATE_OFF;
+
mInfo.ownerUid = mOwnerUid;
mInfo.ownerPackageName = mOwnerPackageName;
}
diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
index ba21b7882afd..af716242210e 100755
--- a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
@@ -51,6 +51,8 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction {
private static final int STATE_WAITING_FOR_OSD_NAME = 3;
// State in which the action is waiting for gathering vendor id of non-local devices.
private static final int STATE_WAITING_FOR_VENDOR_ID = 4;
+ // State in which the action is waiting for devices to be ready
+ private static final int STATE_WAITING_FOR_DEVICES = 5;
/**
* Interface used to report result of device discovery.
@@ -89,16 +91,28 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction {
private final DeviceDiscoveryCallback mCallback;
private int mProcessedDeviceCount = 0;
private int mTimeoutRetry = 0;
- private boolean mIsTvDevice = source().mService.isTvDevice();
+ private boolean mIsTvDevice = localDevice().mService.isTvDevice();
+ private final int mDelayPeriod;
/**
* Constructor.
*
* @param source an instance of {@link HdmiCecLocalDevice}.
+ * @param delay delay action for this period between query Physical Address and polling
*/
- DeviceDiscoveryAction(HdmiCecLocalDevice source, DeviceDiscoveryCallback callback) {
+ DeviceDiscoveryAction(HdmiCecLocalDevice source, DeviceDiscoveryCallback callback, int delay) {
super(source);
mCallback = Preconditions.checkNotNull(callback);
+ mDelayPeriod = delay;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param source an instance of {@link HdmiCecLocalDevice}.
+ */
+ DeviceDiscoveryAction(HdmiCecLocalDevice source, DeviceDiscoveryCallback callback) {
+ this(source, callback, 0);
}
@Override
@@ -117,7 +131,11 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction {
Slog.v(TAG, "Device detected: " + ackedAddress);
allocateDevices(ackedAddress);
- startPhysicalAddressStage();
+ if (mDelayPeriod > 0) {
+ startToDelayAction();
+ } else {
+ startPhysicalAddressStage();
+ }
}
}, Constants.POLL_ITERATION_REVERSE_ORDER
| Constants.POLL_STRATEGY_REMOTES_DEVICES, HdmiConfig.DEVICE_POLLING_RETRY);
@@ -131,6 +149,13 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction {
}
}
+ private void startToDelayAction() {
+ Slog.v(TAG, "Waiting for connected devices to be ready");
+ mState = STATE_WAITING_FOR_DEVICES;
+
+ checkAndProceedStage();
+ }
+
private void startPhysicalAddressStage() {
Slog.v(TAG, "Start [Physical Address Stage]:" + mDevices.size());
mProcessedDeviceCount = 0;
@@ -159,6 +184,11 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction {
addTimer(mState, HdmiConfig.TIMEOUT_MS);
}
+ private void delayActionWithTimePeriod(int timeDelay) {
+ mActionTimer.clearTimerMessage();
+ addTimer(mState, timeDelay);
+ }
+
private void startOsdNameStage() {
Slog.v(TAG, "Start [Osd Name Stage]:" + mDevices.size());
mProcessedDeviceCount = 0;
@@ -385,6 +415,9 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction {
private void sendQueryCommand() {
int address = mDevices.get(mProcessedDeviceCount).mLogicalAddress;
switch (mState) {
+ case STATE_WAITING_FOR_DEVICES:
+ delayActionWithTimePeriod(mDelayPeriod);
+ return;
case STATE_WAITING_FOR_PHYSICAL_ADDRESS:
queryPhysicalAddress(address);
return;
@@ -405,6 +438,10 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction {
return;
}
+ if (mState == STATE_WAITING_FOR_DEVICES) {
+ startPhysicalAddressStage();
+ return;
+ }
if (++mTimeoutRetry < HdmiConfig.TIMEOUT_RETRY) {
sendQueryCommand();
return;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index e777ce8166ac..86be585e5d23 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -77,7 +77,7 @@ final class HdmiCecController {
private static final int NUM_LOGICAL_ADDRESS = 16;
- private static final int MAX_CEC_MESSAGE_HISTORY = 20;
+ private static final int MAX_CEC_MESSAGE_HISTORY = 200;
// Predicate for whether the given logical address is remote device's one or not.
private final Predicate<Integer> mRemoteDeviceAddressPredicate = new Predicate<Integer>() {
@@ -682,7 +682,7 @@ final class HdmiCecController {
void dump(final IndentingPrintWriter pw) {
for (int i = 0; i < mLocalDevices.size(); ++i) {
- pw.println("HdmiCecLocalDevice #" + i + ":");
+ pw.println("HdmiCecLocalDevice #" + mLocalDevices.keyAt(i) + ":");
pw.increaseIndent();
mLocalDevices.valueAt(i).dump(pw);
pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 0e4e3342451c..5c1b3deb9955 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -26,22 +26,29 @@ import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.hdmi.IHdmiControlCallback;
import android.media.AudioDeviceInfo;
+import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.tv.TvContract;
import android.os.SystemProperties;
+import android.provider.Settings.Global;
import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.hdmi.Constants.AudioCodec;
import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
+import java.util.stream.Collectors;
+
/**
* Represent a logical device of type {@link HdmiDeviceInfo#DEVICE_AUDIO_SYSTEM} residing in Android
@@ -83,10 +90,10 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) {
super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
- mSystemAudioControlFeatureEnabled = true;
- // TODO(amyjojo) make System Audio Control controllable by users
- /*mSystemAudioControlFeatureEnabled =
- mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);*/
+ mRoutingControlFeatureEnabled =
+ mService.readBooleanSetting(Global.HDMI_CEC_SWITCH_ENABLED, true);
+ mSystemAudioControlFeatureEnabled =
+ mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);
// TODO(amyjojo): make the map ro property.
mTvInputs.put(Constants.CEC_SWITCH_HDMI1,
"com.droidlogic.tvinput/.services.Hdmi1InputService/HW5");
@@ -267,7 +274,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
int systemAudioOnPowerOnProp, boolean lastSystemAudioControlStatus) {
if ((systemAudioOnPowerOnProp == ALWAYS_SYSTEM_AUDIO_CONTROL_ON_POWER_ON)
|| ((systemAudioOnPowerOnProp == USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON)
- && lastSystemAudioControlStatus)) {
+ && lastSystemAudioControlStatus && isSystemAudioControlFeatureEnabled())) {
addAndStartAction(new SystemAudioInitiationActionFromAvr(this));
}
}
@@ -400,8 +407,11 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
@ServiceThreadOnly
protected boolean handleGiveAudioStatus(HdmiCecMessage message) {
assertRunOnServiceThread();
-
- reportAudioStatus(message);
+ if (isSystemAudioControlFeatureEnabled()) {
+ reportAudioStatus(message.getSource());
+ } else {
+ mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
+ }
return true;
}
@@ -478,14 +488,91 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
private byte[] getSupportedShortAudioDescriptors(
AudioDeviceInfo deviceInfo, @AudioCodec int[] audioFormatCodes) {
- // TODO(b/80297701) implement
- return new byte[] {};
+ ArrayList<byte[]> sads = new ArrayList<>(audioFormatCodes.length);
+ for (@AudioCodec int audioFormatCode : audioFormatCodes) {
+ byte[] sad = getSupportedShortAudioDescriptor(deviceInfo, audioFormatCode);
+ if (sad != null) {
+ if (sad.length == 3) {
+
+ sads.add(sad);
+ } else {
+ HdmiLogger.warning(
+ "Dropping Short Audio Descriptor with length %d for requested codec %x",
+ sad.length, audioFormatCode);
+ }
+ }
+ }
+ // Short Audio Descriptors are always 3 bytes long.
+ byte[] bytes = new byte[sads.size() * 3];
+ int index = 0;
+ for (byte[] sad : sads) {
+ System.arraycopy(sad, 0, bytes, index, 3);
+ index += 3;
+ }
+ return bytes;
+ }
+
+ /**
+ * Returns a 3 byte short audio descriptor as described in CEC 1.4 table 29 or null if the
+ * audioFormatCode is not supported.
+ */
+ @Nullable
+ private byte[] getSupportedShortAudioDescriptor(
+ AudioDeviceInfo deviceInfo, @AudioCodec int audioFormatCode) {
+ switch (audioFormatCode) {
+ case Constants.AUDIO_CODEC_NONE: {
+ return null;
+ }
+ case Constants.AUDIO_CODEC_LPCM: {
+ return getLpcmShortAudioDescriptor(deviceInfo);
+ }
+ // TODO(b/80297701): implement the rest of the codecs
+ case Constants.AUDIO_CODEC_DD:
+ case Constants.AUDIO_CODEC_MPEG1:
+ case Constants.AUDIO_CODEC_MP3:
+ case Constants.AUDIO_CODEC_MPEG2:
+ case Constants.AUDIO_CODEC_AAC:
+ case Constants.AUDIO_CODEC_DTS:
+ case Constants.AUDIO_CODEC_ATRAC:
+ case Constants.AUDIO_CODEC_ONEBITAUDIO:
+ case Constants.AUDIO_CODEC_DDP:
+ case Constants.AUDIO_CODEC_DTSHD:
+ case Constants.AUDIO_CODEC_TRUEHD:
+ case Constants.AUDIO_CODEC_DST:
+ case Constants.AUDIO_CODEC_WMAPRO:
+ default: {
+ return null;
+ }
+ }
+ }
+
+ @Nullable
+ private byte[] getLpcmShortAudioDescriptor(AudioDeviceInfo deviceInfo) {
+ // TODO(b/80297701): implement
+ return null;
}
@Nullable
private AudioDeviceInfo getSystemAudioDeviceInfo() {
- // TODO(b/80297701) implement
- // Get the audio device used for system audio mode.
+ AudioManager audioManager = mService.getContext().getSystemService(AudioManager.class);
+ if (audioManager == null) {
+ HdmiLogger.error(
+ "Error getting system audio device because AudioManager not available.");
+ return null;
+ }
+ AudioDeviceInfo[] devices = audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS);
+ HdmiLogger.debug("Found %d audio input devices", devices.length);
+ for (AudioDeviceInfo device : devices) {
+ HdmiLogger.debug("%s at port %s", device.getProductName(), device.getPort());
+ HdmiLogger.debug("Supported encodings are %s",
+ Arrays.stream(device.getEncodings()).mapToObj(
+ AudioFormat::toLogFriendlyEncoding
+ ).collect(Collectors.joining(", ")));
+ // TODO(b/80297701) use the actual device type that system audio mode is connected to.
+ if (device.getType() == AudioDeviceInfo.TYPE_HDMI_ARC) {
+ return device;
+ }
+ }
return null;
}
@@ -583,17 +670,20 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
.setWiredDeviceConnectionState(AudioSystem.DEVICE_IN_HDMI, enabled ? 1 : 0, "", "");
}
- private void reportAudioStatus(HdmiCecMessage message) {
+ void reportAudioStatus(int source) {
assertRunOnServiceThread();
int volume = mService.getAudioManager().getStreamVolume(AudioManager.STREAM_MUSIC);
boolean mute = mService.getAudioManager().isStreamMute(AudioManager.STREAM_MUSIC);
int maxVolume = mService.getAudioManager().getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ int minVolume = mService.getAudioManager().getStreamMinVolume(AudioManager.STREAM_MUSIC);
int scaledVolume = VolumeControlAction.scaleToCecVolume(volume, maxVolume);
+ HdmiLogger.debug("Reporting volume %i (%i-%i) as CEC volume %i", volume,
+ minVolume, maxVolume, scaledVolume);
mService.sendCecCommand(
HdmiCecMessageBuilder.buildReportAudioStatus(
- mAddress, message.getSource(), scaledVolume, mute));
+ mAddress, source, scaledVolume, mute));
}
/**
@@ -688,6 +778,13 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
HdmiLogger.debug("[A]UpdateSystemAudio mode[on=%b] output=[%X]", on, device);
}
+ void onSystemAduioControlFeatureSupportChanged(boolean enabled) {
+ setSystemAudioControlFeatureEnabled(enabled);
+ if (enabled) {
+ addAndStartAction(new SystemAudioInitiationActionFromAvr(this));
+ }
+ }
+
@ServiceThreadOnly
void setSystemAudioControlFeatureEnabled(boolean enabled) {
assertRunOnServiceThread();
@@ -697,6 +794,14 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
}
@ServiceThreadOnly
+ void setRoutingControlFeatureEnables(boolean enabled) {
+ assertRunOnServiceThread();
+ synchronized (mLock) {
+ mRoutingControlFeatureEnabled = enabled;
+ }
+ }
+
+ @ServiceThreadOnly
void doManualPortSwitching(int portId, IHdmiControlCallback callback) {
assertRunOnServiceThread();
// TODO: validate port ID
@@ -831,6 +936,10 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
}
protected void routeToInputFromPortId(int portId) {
+ if (!isRoutingControlFeatureEnabled()) {
+ HdmiLogger.debug("Routing Control Feature is not enabled.");
+ return;
+ }
if (mArcIntentUsed) {
routeToTvInputFromPortId(portId);
} else {
@@ -978,4 +1087,20 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
}
mDeviceInfos.clear();
}
+
+ @Override
+ protected void dump(IndentingPrintWriter pw) {
+ pw.println("HdmiCecLocalDeviceAudioSystem:");
+ pw.increaseIndent();
+ pw.println("mSystemAudioActivated: " + mSystemAudioActivated);
+ pw.println("mSystemAudioControlFeatureEnabled: " + mSystemAudioControlFeatureEnabled);
+ pw.println("mTvSystemAudioModeSupport: " + mTvSystemAudioModeSupport);
+ pw.println("mArcEstablished: " + mArcEstablished);
+ pw.println("mArcIntentUsed: " + mArcIntentUsed);
+ HdmiUtils.dumpMap(pw, "mTvInputs:", mTvInputs);
+ HdmiUtils.dumpSparseArray(pw, "mDeviceInfos:", mDeviceInfos);
+ pw.decreaseIndent();
+ super.dump(pw);
+ }
+
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index a95f7f1f3f3d..cbddaf53348a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -66,6 +66,10 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
@LocalActivePort
protected int mLocalActivePort = Constants.CEC_SWITCH_HOME;
+ // Whether the Routing Coutrol feature is enabled or not. True by default.
+ @GuardedBy("mLock")
+ protected boolean mRoutingControlFeatureEnabled;
+
protected HdmiCecLocalDeviceSource(HdmiControlService service, int deviceType) {
super(service, deviceType);
}
@@ -123,7 +127,9 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
}
setIsActiveSource(physicalAddress == mService.getPhysicalAddress());
updateDevicePowerStatus(logicalAddress, HdmiControlManager.POWER_STATUS_ON);
- switchInputOnReceivingNewActivePath(physicalAddress);
+ if (isRoutingControlFeatureEnabled()) {
+ switchInputOnReceivingNewActivePath(physicalAddress);
+ }
return true;
}
@@ -153,6 +159,10 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
@ServiceThreadOnly
protected boolean handleRoutingChange(HdmiCecMessage message) {
assertRunOnServiceThread();
+ if (!isRoutingControlFeatureEnabled()) {
+ mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
+ return true;
+ }
int newPath = HdmiUtils.twoBytesToInt(message.getParams(), 2);
// if the current device is a pure playback device
if (!mIsSwitchDevice
@@ -168,6 +178,10 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
@ServiceThreadOnly
protected boolean handleRoutingInformation(HdmiCecMessage message) {
assertRunOnServiceThread();
+ if (!isRoutingControlFeatureEnabled()) {
+ mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED);
+ return true;
+ }
int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
// if the current device is a pure playback device
if (!mIsSwitchDevice
@@ -279,6 +293,12 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
}
}
+ boolean isRoutingControlFeatureEnabled() {
+ synchronized (mLock) {
+ return mRoutingControlFeatureEnabled;
+ }
+ }
+
// Check if the device is trying to switch to the same input that is active right now.
// This can help avoid redundant port switching.
protected boolean isSwitchingToTheSameInput(@LocalActivePort int activePort) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
index c0056158a9c5..f8b39627f236 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessage.java
@@ -17,6 +17,7 @@
package com.android.server.hdmi;
import android.annotation.Nullable;
+
import libcore.util.EmptyArray;
import java.util.Arrays;
@@ -111,12 +112,11 @@ public final class HdmiCecMessage {
@Override
public String toString() {
StringBuffer s = new StringBuffer();
- s.append(String.format("<%s> src: %d, dst: %d",
- opcodeToString(mOpcode), mSource, mDestination));
+ s.append(String.format("<%s> %X%X:%02X",
+ opcodeToString(mOpcode), mSource, mDestination, mOpcode));
if (mParams.length > 0) {
- s.append(", params:");
for (byte data : mParams) {
- s.append(String.format(" %02X", data));
+ s.append(String.format(":%02X", data));
}
}
return s.toString();
@@ -133,7 +133,7 @@ public final class HdmiCecMessage {
case Constants.MESSAGE_TUNER_STEP_DECREMENT:
return "Tuner Step Decrement";
case Constants.MESSAGE_TUNER_DEVICE_STATUS:
- return "Tuner Device Staus";
+ return "Tuner Device Status";
case Constants.MESSAGE_GIVE_TUNER_DEVICE_STATUS:
return "Give Tuner Device Status";
case Constants.MESSAGE_RECORD_ON:
@@ -207,7 +207,7 @@ public final class HdmiCecMessage {
case Constants.MESSAGE_DEVICE_VENDOR_ID:
return "Device Vendor Id";
case Constants.MESSAGE_VENDOR_COMMAND:
- return "Vendor Commandn";
+ return "Vendor Command";
case Constants.MESSAGE_VENDOR_REMOTE_BUTTON_DOWN:
return "Vendor Remote Button Down";
case Constants.MESSAGE_VENDOR_REMOTE_BUTTON_UP:
@@ -215,7 +215,7 @@ public final class HdmiCecMessage {
case Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID:
return "Give Device Vendor Id";
case Constants.MESSAGE_MENU_REQUEST:
- return "Menu REquest";
+ return "Menu Request";
case Constants.MESSAGE_MENU_STATUS:
return "Menu Status";
case Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS:
@@ -247,7 +247,7 @@ public final class HdmiCecMessage {
case Constants.MESSAGE_SET_EXTERNAL_TIMER:
return "Set External Timer";
case Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR:
- return "Repot Short Audio Descriptor";
+ return "Report Short Audio Descriptor";
case Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR:
return "Request Short Audio Descriptor";
case Constants.MESSAGE_INITIATE_ARC:
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 2d6e76294e4a..aabe1ad659d6 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -26,6 +26,7 @@ import static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE;
import static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING;
import static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE;
import static com.android.server.hdmi.Constants.OPTION_MHL_SERVICE_CONTROL;
+import static com.android.server.power.ShutdownThread.SHUTDOWN_ACTION_PROPERTY;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
@@ -184,9 +185,10 @@ public class HdmiControlService extends SystemService {
@Override
public void onReceive(Context context, Intent intent) {
assertRunOnServiceThread();
+ boolean isReboot = SystemProperties.get(SHUTDOWN_ACTION_PROPERTY).contains("1");
switch (intent.getAction()) {
case Intent.ACTION_SCREEN_OFF:
- if (isPowerOnOrTransient()) {
+ if (isPowerOnOrTransient() && !isReboot) {
onStandby(STANDBY_SCREEN_OFF);
}
break;
@@ -202,7 +204,7 @@ public class HdmiControlService extends SystemService {
}
break;
case Intent.ACTION_SHUTDOWN:
- if (isPowerOnOrTransient()) {
+ if (isPowerOnOrTransient() && !isReboot) {
onStandby(STANDBY_SHUTDOWN);
}
break;
@@ -345,6 +347,10 @@ public class HdmiControlService extends SystemService {
@Nullable
private Looper mIoLooper;
+ // Thread safe physical address
+ @GuardedBy("mLock")
+ private int mPhysicalAddress = Constants.INVALID_PHYSICAL_ADDRESS;
+
// Last input port before switching to the MHL port. Should switch back to this port
// when the mobile device sends the request one touch play with off.
// Gets invalidated if we go to other port/input.
@@ -564,7 +570,8 @@ public class HdmiControlService extends SystemService {
Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
Global.MHL_INPUT_SWITCHING_ENABLED,
- Global.MHL_POWER_CHARGE_ENABLED
+ Global.MHL_POWER_CHARGE_ENABLED,
+ Global.HDMI_CEC_SWITCH_ENABLED
};
for (String s : settings) {
resolver.registerContentObserver(Global.getUriFor(s), false, mSettingsObserver,
@@ -605,6 +612,14 @@ public class HdmiControlService extends SystemService {
if (isTvDeviceEnabled()) {
tv().setSystemAudioControlFeatureEnabled(enabled);
}
+ if (isAudioSystemDevice()) {
+ audioSystem().onSystemAduioControlFeatureSupportChanged(enabled);
+ }
+ break;
+ case Global.HDMI_CEC_SWITCH_ENABLED:
+ if (isAudioSystemDevice()) {
+ audioSystem().setRoutingControlFeatureEnables(enabled);
+ }
break;
case Global.MHL_INPUT_SWITCHING_ENABLED:
setMhlInputChangeEnabled(enabled);
@@ -734,6 +749,10 @@ public class HdmiControlService extends SystemService {
assertRunOnServiceThread();
HdmiPortInfo[] cecPortInfo = null;
+ synchronized (mLock) {
+ mPhysicalAddress = getPhysicalAddress();
+ }
+
// CEC HAL provides majority of the info while MHL does only MHL support flag for
// each port. Return empty array if CEC HAL didn't provide the info.
if (mCecController != null) {
@@ -1532,6 +1551,14 @@ public class HdmiControlService extends SystemService {
}
@Override
+ public int getPhysicalAddress() {
+ enforceAccessPermission();
+ synchronized (mLock) {
+ return mPhysicalAddress;
+ }
+ }
+
+ @Override
public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) {
enforceAccessPermission();
runOnServiceThread(new Runnable() {
@@ -1834,14 +1861,28 @@ public class HdmiControlService extends SystemService {
Slog.w(TAG, "audio system is not in system audio mode");
return;
}
- int scaledVolume = VolumeControlAction.scaleToCecVolume(volume, maxVolume);
-
- sendCecCommand(HdmiCecMessageBuilder
- .buildReportAudioStatus(
- device.getDeviceInfo().getLogicalAddress(),
- Constants.ADDR_TV,
- scaledVolume,
- isMute));
+ audioSystem().reportAudioStatus(Constants.ADDR_TV);
+ }
+ });
+ }
+
+ @Override
+ public void setSystemAudioModeOnForAudioOnlySource() {
+ enforceAccessPermission();
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ if (!isAudioSystemDevice()) {
+ Slog.e(TAG, "Not an audio system device. Won't set system audio mode on");
+ return;
+ }
+ if (!audioSystem().checkSupportAndSetSystemAudioMode(true)) {
+ Slog.e(TAG, "System Audio Mode is not supported.");
+ return;
+ }
+ sendCecCommand(
+ HdmiCecMessageBuilder.buildSetSystemAudioMode(
+ audioSystem().mAddress, Constants.ADDR_BROADCAST, true));
}
});
}
@@ -1851,27 +1892,28 @@ public class HdmiControlService extends SystemService {
if (!DumpUtils.checkDumpPermission(getContext(), TAG, writer)) return;
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
- pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled);
pw.println("mProhibitMode: " + mProhibitMode);
- if (mCecController != null) {
- pw.println("mCecController: ");
- pw.increaseIndent();
- mCecController.dump(pw);
- pw.decreaseIndent();
- }
+ pw.println("mPowerStatus: " + mPowerStatus);
+
+ // System settings
+ pw.println("System_settings:");
+ pw.increaseIndent();
+ pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled);
+ pw.println("mMhlInputChangeEnabled: " + mMhlInputChangeEnabled);
+ pw.decreaseIndent();
pw.println("mMhlController: ");
pw.increaseIndent();
mMhlController.dump(pw);
pw.decreaseIndent();
- pw.println("mPortInfo: ");
- pw.increaseIndent();
- for (HdmiPortInfo hdmiPortInfo : mPortInfo) {
- pw.println("- " + hdmiPortInfo);
+ HdmiUtils.dumpIterable(pw, "mPortInfo:", mPortInfo);
+ if (mCecController != null) {
+ pw.println("mCecController: ");
+ pw.increaseIndent();
+ mCecController.dump(pw);
+ pw.decreaseIndent();
}
- pw.decreaseIndent();
- pw.println("mPowerStatus: " + mPowerStatus);
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiUtils.java b/services/core/java/com/android/server/hdmi/HdmiUtils.java
index 2a8117fac68d..21106828d43f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiUtils.java
+++ b/services/core/java/com/android/server/hdmi/HdmiUtils.java
@@ -20,9 +20,13 @@ import android.hardware.hdmi.HdmiDeviceInfo;
import android.util.Slog;
import android.util.SparseArray;
+import com.android.internal.util.IndentingPrintWriter;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+
/**
* Various utilities to handle HDMI CEC messages.
@@ -317,4 +321,74 @@ final class HdmiUtils {
info.getPhysicalAddress(), info.getPortId(), info.getDeviceType(),
info.getVendorId(), info.getDisplayName(), newPowerStatus);
}
+
+ /**
+ * Dump a {@link SparseArray} to the print writer.
+ *
+ * <p>The dump is formatted:
+ * <pre>
+ * name:
+ * key = value
+ * key = value
+ * ...
+ * </pre>
+ */
+ static <T> void dumpSparseArray(IndentingPrintWriter pw, String name,
+ SparseArray<T> sparseArray) {
+ printWithTrailingColon(pw, name);
+ pw.increaseIndent();
+ int size = sparseArray.size();
+ for (int i = 0; i < size; i++) {
+ int key = sparseArray.keyAt(i);
+ T value = sparseArray.get(key);
+ pw.printPair(Integer.toString(key), value);
+ pw.println();
+ }
+ pw.decreaseIndent();
+ }
+
+ private static void printWithTrailingColon(IndentingPrintWriter pw, String name) {
+ pw.println(name.endsWith(":") ? name : name.concat(":"));
+ }
+
+ /**
+ * Dump a {@link Map} to the print writer.
+ *
+ * <p>The dump is formatted:
+ * <pre>
+ * name:
+ * key = value
+ * key = value
+ * ...
+ * </pre>
+ */
+ static <K, V> void dumpMap(IndentingPrintWriter pw, String name, Map<K, V> map) {
+ printWithTrailingColon(pw, name);
+ pw.increaseIndent();
+ for (Map.Entry<K, V> entry: map.entrySet()) {
+ pw.printPair(entry.getKey().toString(), entry.getValue());
+ pw.println();
+ }
+ pw.decreaseIndent();
+ }
+
+ /**
+ * Dump a {@link Map} to the print writer.
+ *
+ * <p>The dump is formatted:
+ * <pre>
+ * name:
+ * value
+ * value
+ * ...
+ * </pre>
+ */
+ static <T> void dumpIterable(IndentingPrintWriter pw, String name, Iterable<T> values) {
+ printWithTrailingColon(pw, name);
+ pw.increaseIndent();
+ for (T value : values) {
+ pw.println(value);
+ }
+ pw.decreaseIndent();
+ }
}
diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java
index 86bc9f313551..fe91c63e712b 100644
--- a/services/core/java/com/android/server/location/MockProvider.java
+++ b/services/core/java/com/android/server/location/MockProvider.java
@@ -52,7 +52,6 @@ public class MockProvider extends AbstractLocationProvider {
mExtras = null;
setProperties(properties);
- setEnabled(true);
}
/** Sets the enabled state of this mock provider. */
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 5f56fe59c1f2..177f244129f4 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -462,22 +462,19 @@ class KeyguardController {
mOccluded = false;
mDismissingKeyguardActivity = null;
- // Only the top activity of the focused stack on each display may control it's
- // occluded state.
- final ActivityStack focusedStack = display.getFocusedStack();
- if (focusedStack != null) {
- final ActivityRecord topDismissing =
- focusedStack.getTopDismissingKeyguardActivity();
- mOccluded = focusedStack.topActivityOccludesKeyguard() || (topDismissing != null
- && focusedStack.topRunningActivityLocked() == topDismissing
- && controller.canShowWhileOccluded(
+ final ActivityStack stack = getStackForControllingOccluding(display);
+ if (stack != null) {
+ final ActivityRecord topDismissing = stack.getTopDismissingKeyguardActivity();
+ mOccluded = stack.topActivityOccludesKeyguard() || (topDismissing != null
+ && stack.topRunningActivityLocked() == topDismissing
+ && controller.canShowWhileOccluded(
true /* dismissKeyguard */,
false /* showWhenLocked */));
- if (focusedStack.getTopDismissingKeyguardActivity() != null) {
- mDismissingKeyguardActivity = focusedStack.getTopDismissingKeyguardActivity();
+ if (stack.getTopDismissingKeyguardActivity() != null) {
+ mDismissingKeyguardActivity = stack.getTopDismissingKeyguardActivity();
}
- mOccluded |= controller.mWindowManager.isShowingDream();
}
+ mOccluded |= controller.mWindowManager.isShowingDream();
// TODO(b/113840485): Handle app transition for individual display, and apply occluded
// state change to secondary displays.
@@ -492,6 +489,23 @@ class KeyguardController {
}
}
+ /**
+ * Gets the stack used to check the occluded state.
+ * <p>
+ * Only the top non-pinned activity of the focusable stack on each display can control its
+ * occlusion state.
+ */
+ private ActivityStack getStackForControllingOccluding(ActivityDisplay display) {
+ for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = display.getChildAt(stackNdx);
+ if (stack != null && stack.isFocusableAndVisible()
+ && !stack.inPinnedWindowingMode()) {
+ return stack;
+ }
+ }
+ return null;
+ }
+
void dumpStatus(PrintWriter pw, String prefix) {
final StringBuilder sb = new StringBuilder();
sb.append(prefix);
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index b290bc516320..bce944d88a73 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -856,7 +856,7 @@ struct GnssMeasurementCallback : public IGnssMeasurementCallback_V2_0 {
Return<void> GnssMeasurementCallback::gnssMeasurementCb_2_0(
const IGnssMeasurementCallback_V2_0::GnssData& data) {
- // TODO(b/119571122): implement gnssMeasurementCb_2_0
+ translateAndSetGnssData(data);
return Void();
}
@@ -894,9 +894,8 @@ size_t GnssMeasurementCallback::getMeasurementCount<IGnssMeasurementCallback_V1_
return data.measurementCount;
}
-template<>
-size_t GnssMeasurementCallback::getMeasurementCount<IGnssMeasurementCallback_V1_1::GnssData>
- (const IGnssMeasurementCallback_V1_1::GnssData& data) {
+template<class T>
+size_t GnssMeasurementCallback::getMeasurementCount(const T& data) {
return data.measurements.size();
}
@@ -958,6 +957,17 @@ void GnssMeasurementCallback::translateSingleGnssMeasurement
ADR_STATE_HALF_CYCLE_REPORTED));
}
+// Preallocate object as: JavaObject object(env, "android/location/GnssMeasurement");
+template<>
+void GnssMeasurementCallback::translateSingleGnssMeasurement
+ <IGnssMeasurementCallback_V2_0::GnssMeasurement>(
+ const IGnssMeasurementCallback_V2_0::GnssMeasurement* measurement_V2_0,
+ JavaObject& object) {
+ translateSingleGnssMeasurement(&(measurement_V2_0->v1_1), object);
+
+ SET(CodeType, (static_cast<int32_t>(measurement_V2_0->codeType)));
+}
+
jobject GnssMeasurementCallback::translateGnssClock(
JNIEnv* env, const IGnssMeasurementCallback_V1_0::GnssClock* clock) {
JavaObject object(env, "android/location/GnssClock");