diff --git a/core/api/system-current.txt b/core/api/system-current.txt index a1f751fb82d0b..5050c40cebe90 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -75,6 +75,7 @@ package android { field public static final String BIND_TRANSLATION_SERVICE = "android.permission.BIND_TRANSLATION_SERVICE"; field public static final String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT"; field public static final String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE"; + field public static final String BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE = "android.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE"; field public static final String BLUETOOTH_MAP = "android.permission.BLUETOOTH_MAP"; field public static final String BRICK = "android.permission.BRICK"; field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE"; @@ -187,6 +188,7 @@ package android { field public static final String MANAGE_USB = "android.permission.MANAGE_USB"; field public static final String MANAGE_USERS = "android.permission.MANAGE_USERS"; field public static final String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE"; + field public static final String MANAGE_WALLPAPER_EFFECTS_GENERATION = "android.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION"; field public static final String MANAGE_WEAK_ESCROW_TOKEN = "android.permission.MANAGE_WEAK_ESCROW_TOKEN"; field public static final String MANAGE_WIFI_AUTO_JOIN = "android.permission.MANAGE_WIFI_AUTO_JOIN"; field public static final String MANAGE_WIFI_COUNTRY_CODE = "android.permission.MANAGE_WIFI_COUNTRY_CODE"; @@ -2533,6 +2535,107 @@ package android.app.usage { } +package android.app.wallpapereffectsgeneration { + + public final class CameraAttributes implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public float[] getAnchorPointInOutputUvSpace(); + method @NonNull public float[] getAnchorPointInWorldSpace(); + method public float getCameraOrbitPitchDegrees(); + method public float getCameraOrbitYawDegrees(); + method public float getDollyDistanceInWorldSpace(); + method public float getFrustumFarInWorldSpace(); + method public float getFrustumNearInWorldSpace(); + method public float getVerticalFovDegrees(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public static final class CameraAttributes.Builder { + ctor public CameraAttributes.Builder(@NonNull float[], @NonNull float[]); + method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes build(); + method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes.Builder setCameraOrbitPitchDegrees(@FloatRange(from=-90.0F, to=90.0f) float); + method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes.Builder setCameraOrbitYawDegrees(@FloatRange(from=-180.0F, to=180.0f) float); + method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes.Builder setDollyDistanceInWorldSpace(float); + method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes.Builder setFrustumFarInWorldSpace(@FloatRange(from=0.0f) float); + method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes.Builder setFrustumNearInWorldSpace(@FloatRange(from=0.0f) float); + method @NonNull public android.app.wallpapereffectsgeneration.CameraAttributes.Builder setVerticalFovDegrees(@FloatRange(from=0.0f, to=180.0f, fromInclusive=false) float); + } + + public final class CinematicEffectRequest implements android.os.Parcelable { + ctor public CinematicEffectRequest(@NonNull String, @NonNull android.graphics.Bitmap); + method public int describeContents(); + method @NonNull public android.graphics.Bitmap getBitmap(); + method @NonNull public String getTaskId(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public final class CinematicEffectResponse implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public android.app.wallpapereffectsgeneration.CameraAttributes getEndKeyFrame(); + method public int getImageContentType(); + method @Nullable public android.app.wallpapereffectsgeneration.CameraAttributes getStartKeyFrame(); + method public int getStatusCode(); + method @NonNull public String getTaskId(); + method @NonNull public java.util.List getTexturedMeshes(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int CINEMATIC_EFFECT_STATUS_ERROR = 2; // 0x2 + field public static final int CINEMATIC_EFFECT_STATUS_NOT_READY = 3; // 0x3 + field public static final int CINEMATIC_EFFECT_STATUS_OK = 1; // 0x1 + field public static final int CINEMATIC_EFFECT_STATUS_PENDING = 4; // 0x4 + field public static final int CINEMATIC_EFFECT_STATUS_TOO_MANY_REQUESTS = 5; // 0x5 + field public static final int CINEMATIC_EFFECT_STATUS_UNKNOWN = 0; // 0x0 + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + field public static final int IMAGE_CONTENT_TYPE_LANDSCAPE = 2; // 0x2 + field public static final int IMAGE_CONTENT_TYPE_OTHER = 3; // 0x3 + field public static final int IMAGE_CONTENT_TYPE_PEOPLE_PORTRAIT = 1; // 0x1 + field public static final int IMAGE_CONTENT_TYPE_UNKNOWN = 0; // 0x0 + } + + public static final class CinematicEffectResponse.Builder { + ctor public CinematicEffectResponse.Builder(int, @NonNull String); + method @NonNull public android.app.wallpapereffectsgeneration.CinematicEffectResponse build(); + method @NonNull public android.app.wallpapereffectsgeneration.CinematicEffectResponse.Builder setEndKeyFrame(@Nullable android.app.wallpapereffectsgeneration.CameraAttributes); + method @NonNull public android.app.wallpapereffectsgeneration.CinematicEffectResponse.Builder setImageContentType(int); + method @NonNull public android.app.wallpapereffectsgeneration.CinematicEffectResponse.Builder setStartKeyFrame(@Nullable android.app.wallpapereffectsgeneration.CameraAttributes); + method @NonNull public android.app.wallpapereffectsgeneration.CinematicEffectResponse.Builder setTexturedMeshes(@NonNull java.util.List); + } + + public final class TexturedMesh implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.graphics.Bitmap getBitmap(); + method @NonNull public int[] getIndices(); + method @NonNull public int getIndicesLayoutType(); + method @NonNull public float[] getVertices(); + method @NonNull public int getVerticesLayoutType(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + field public static final int INDICES_LAYOUT_TRIANGLES = 1; // 0x1 + field public static final int INDICES_LAYOUT_UNDEFINED = 0; // 0x0 + field public static final int VERTICES_LAYOUT_POSITION3_UV2 = 1; // 0x1 + field public static final int VERTICES_LAYOUT_UNDEFINED = 0; // 0x0 + } + + public static final class TexturedMesh.Builder { + ctor public TexturedMesh.Builder(@NonNull android.graphics.Bitmap); + method @NonNull public android.app.wallpapereffectsgeneration.TexturedMesh build(); + method @NonNull public android.app.wallpapereffectsgeneration.TexturedMesh.Builder setIndices(@NonNull int[]); + method @NonNull public android.app.wallpapereffectsgeneration.TexturedMesh.Builder setIndicesLayoutType(int); + method @NonNull public android.app.wallpapereffectsgeneration.TexturedMesh.Builder setVertices(@NonNull float[]); + method @NonNull public android.app.wallpapereffectsgeneration.TexturedMesh.Builder setVerticesLayoutType(int); + } + + public final class WallpaperEffectsGenerationManager { + method @RequiresPermission(android.Manifest.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION) public void generateCinematicEffect(@NonNull android.app.wallpapereffectsgeneration.CinematicEffectRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.wallpapereffectsgeneration.WallpaperEffectsGenerationManager.CinematicEffectListener); + } + + public static interface WallpaperEffectsGenerationManager.CinematicEffectListener { + method public void onCinematicEffectGenerated(@NonNull android.app.wallpapereffectsgeneration.CinematicEffectResponse); + } + +} + package android.apphibernation { public class AppHibernationManager { @@ -2716,6 +2819,7 @@ package android.content { field public static final String UI_TRANSLATION_SERVICE = "ui_translation"; field public static final String UWB_SERVICE = "uwb"; field public static final String VR_SERVICE = "vrmanager"; + field public static final String WALLPAPER_EFFECTS_GENERATION_SERVICE = "wallpaper_effects_generation"; field public static final String WIFI_NL80211_SERVICE = "wifinl80211"; field @Deprecated public static final String WIFI_RTT_SERVICE = "rttmanager"; field public static final String WIFI_SCANNING_SERVICE = "wifiscanner"; @@ -11648,6 +11752,17 @@ package android.service.wallpaper { } +package android.service.wallpapereffectsgeneration { + + public abstract class WallpaperEffectsGenerationService extends android.app.Service { + ctor public WallpaperEffectsGenerationService(); + method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent); + method public abstract void onGenerateCinematicEffect(@NonNull android.app.wallpapereffectsgeneration.CinematicEffectRequest); + method public final void returnCinematicEffectResponse(@NonNull android.app.wallpapereffectsgeneration.CinematicEffectResponse); + } + +} + package android.service.watchdog { public abstract class ExplicitHealthCheckService extends android.app.Service { diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index dd832c81d529e..2d7489afc6c70 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -51,6 +51,8 @@ import android.app.usage.IUsageStatsManager; import android.app.usage.NetworkStatsManager; import android.app.usage.StorageStatsManager; import android.app.usage.UsageStatsManager; +import android.app.wallpapereffectsgeneration.IWallpaperEffectsGenerationManager; +import android.app.wallpapereffectsgeneration.WallpaperEffectsGenerationManager; import android.apphibernation.AppHibernationManager; import android.appwidget.AppWidgetManager; import android.bluetooth.BluetoothFrameworkInitializer; @@ -1298,6 +1300,20 @@ public final class SystemServiceRegistry { } }); + registerService(Context.WALLPAPER_EFFECTS_GENERATION_SERVICE, + WallpaperEffectsGenerationManager.class, + new CachedServiceFetcher() { + @Override + public WallpaperEffectsGenerationManager createService(ContextImpl ctx) + throws ServiceNotFoundException { + IBinder b = ServiceManager.getService( + Context.WALLPAPER_EFFECTS_GENERATION_SERVICE); + return b == null ? null : + new WallpaperEffectsGenerationManager( + IWallpaperEffectsGenerationManager.Stub.asInterface(b)); + } + }); + registerService(Context.VR_SERVICE, VrManager.class, new CachedServiceFetcher() { @Override public VrManager createService(ContextImpl ctx) throws ServiceNotFoundException { diff --git a/core/java/android/app/wallpapereffectsgeneration/CameraAttributes.java b/core/java/android/app/wallpapereffectsgeneration/CameraAttributes.java new file mode 100644 index 0000000000000..dfbc7a4c32761 --- /dev/null +++ b/core/java/android/app/wallpapereffectsgeneration/CameraAttributes.java @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.wallpapereffectsgeneration; + +import android.annotation.FloatRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Representing the position and other parameters of camera of a single frame. + * + * @hide + */ +@SystemApi +public final class CameraAttributes implements Parcelable { + /** + * The location of the anchor within the 3D scene. + * Expecting 3 floats representing the x, y, z coordinates + * of the anchor point. + */ + @NonNull + private float[] mAnchorPointInWorldSpace; + /** + * Where the anchor point should project to in the output image. + * Expecting 2 floats representing the u,v coordinates of the + * anchor point. + */ + @NonNull + private float[] mAnchorPointInOutputUvSpace; + /** + * Specifies the amount of yaw orbit rotation the camera should perform + * around the anchor point in world space. + */ + private float mCameraOrbitYawDegrees; + /** + * Specifies the amount of pitch orbit rotation the camera should perform + * around the anchor point in world space. + */ + private float mCameraOrbitPitchDegrees; + /** + * Specifies by how much the camera should be placed towards the anchor + * point in world space, which is also called dolly distance. + */ + private float mDollyDistanceInWorldSpace; + /** + * Specifies the vertical fov degrees of the virtual image. + */ + private float mVerticalFovDegrees; + /** + * The frustum of near plane. + */ + private float mFrustumNearInWorldSpace; + /** + * The frustum of far plane. + */ + private float mFrustumFarInWorldSpace; + + private CameraAttributes(Parcel in) { + this.mCameraOrbitYawDegrees = in.readFloat(); + this.mCameraOrbitPitchDegrees = in.readFloat(); + this.mDollyDistanceInWorldSpace = in.readFloat(); + this.mVerticalFovDegrees = in.readFloat(); + this.mFrustumNearInWorldSpace = in.readFloat(); + this.mFrustumFarInWorldSpace = in.readFloat(); + this.mAnchorPointInWorldSpace = in.createFloatArray(); + this.mAnchorPointInOutputUvSpace = in.createFloatArray(); + } + + private CameraAttributes(float[] anchorPointInWorldSpace, float[] anchorPointInOutputUvSpace, + float cameraOrbitYawDegrees, float cameraOrbitPitchDegrees, + float dollyDistanceInWorldSpace, + float verticalFovDegrees, float frustumNearInWorldSpace, float frustumFarInWorldSpace) { + mAnchorPointInWorldSpace = anchorPointInWorldSpace; + mAnchorPointInOutputUvSpace = anchorPointInOutputUvSpace; + mCameraOrbitYawDegrees = cameraOrbitYawDegrees; + mCameraOrbitPitchDegrees = cameraOrbitPitchDegrees; + mDollyDistanceInWorldSpace = dollyDistanceInWorldSpace; + mVerticalFovDegrees = verticalFovDegrees; + mFrustumNearInWorldSpace = frustumNearInWorldSpace; + mFrustumFarInWorldSpace = frustumFarInWorldSpace; + } + + /** + * Get the location of the anchor within the 3D scene. The response float array contains + * 3 floats representing the x, y, z coordinates + */ + @NonNull + public float[] getAnchorPointInWorldSpace() { + return mAnchorPointInWorldSpace; + } + + /** + * Get where the anchor point should project to in the output image. The response float + * array contains 2 floats representing the u,v coordinates of the anchor point. + */ + @NonNull + public float[] getAnchorPointInOutputUvSpace() { + return mAnchorPointInOutputUvSpace; + } + + /** + * Get the camera yaw orbit rotation. + */ + public float getCameraOrbitYawDegrees() { + return mCameraOrbitYawDegrees; + } + + /** + * Get the camera pitch orbit rotation. + */ + public float getCameraOrbitPitchDegrees() { + return mCameraOrbitPitchDegrees; + } + + /** + * Get how many units the camera should be placed towards the anchor point in world space. + */ + public float getDollyDistanceInWorldSpace() { + return mDollyDistanceInWorldSpace; + } + + /** + * Get the camera vertical fov degrees. + */ + public float getVerticalFovDegrees() { + return mVerticalFovDegrees; + } + + /** + * Get the frustum in near plane. + */ + public float getFrustumNearInWorldSpace() { + return mFrustumNearInWorldSpace; + } + + /** + * Get the frustum in far plane. + */ + public float getFrustumFarInWorldSpace() { + return mFrustumFarInWorldSpace; + } + + @NonNull + public static final Creator CREATOR = new Creator() { + @Override + public CameraAttributes createFromParcel(Parcel in) { + return new CameraAttributes(in); + } + + @Override + public CameraAttributes[] newArray(int size) { + return new CameraAttributes[size]; + } + }; + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeFloat(mCameraOrbitYawDegrees); + out.writeFloat(mCameraOrbitPitchDegrees); + out.writeFloat(mDollyDistanceInWorldSpace); + out.writeFloat(mVerticalFovDegrees); + out.writeFloat(mFrustumNearInWorldSpace); + out.writeFloat(mFrustumFarInWorldSpace); + out.writeFloatArray(mAnchorPointInWorldSpace); + out.writeFloatArray(mAnchorPointInOutputUvSpace); + } + + @Override + public int describeContents() { + return 0; + } + + /** + * Builder for {@link CameraAttributes}. + * + * @hide + */ + @SystemApi + public static final class Builder { + @NonNull + private float[] mAnchorPointInWorldSpace; + @NonNull + private float[] mAnchorPointInOutputUvSpace; + private float mCameraOrbitYawDegrees; + private float mCameraOrbitPitchDegrees; + private float mDollyDistanceInWorldSpace; + private float mVerticalFovDegrees; + private float mFrustumNearInWorldSpace; + private float mFrustumFarInWorldSpace; + + /** + * Constructor with anchor point in world space and anchor point in output image + * space. + * + * @param anchorPointInWorldSpace the location of the anchor within the 3D scene. The + * float array contains 3 floats representing the x, y, z coordinates. + * @param anchorPointInOutputUvSpace where the anchor point should project to in the + * output image. The float array contains 2 floats representing the u,v coordinates + * of the anchor point. + * + * @hide + */ + @SystemApi + public Builder(@NonNull float[] anchorPointInWorldSpace, + @NonNull float[] anchorPointInOutputUvSpace) { + mAnchorPointInWorldSpace = anchorPointInWorldSpace; + mAnchorPointInOutputUvSpace = anchorPointInOutputUvSpace; + } + + /** + * Sets the camera orbit yaw rotation. + */ + @NonNull + public Builder setCameraOrbitYawDegrees( + @FloatRange(from = -180.0f, to = 180.0f) float cameraOrbitYawDegrees) { + mCameraOrbitYawDegrees = cameraOrbitYawDegrees; + return this; + } + + /** + * Sets the camera orbit pitch rotation. + */ + @NonNull + public Builder setCameraOrbitPitchDegrees( + @FloatRange(from = -90.0f, to = 90.0f) float cameraOrbitPitchDegrees) { + mCameraOrbitPitchDegrees = cameraOrbitPitchDegrees; + return this; + } + + /** + * Sets the camera dolly distance. + */ + @NonNull + public Builder setDollyDistanceInWorldSpace(float dollyDistanceInWorldSpace) { + mDollyDistanceInWorldSpace = dollyDistanceInWorldSpace; + return this; + } + + /** + * Sets the camera vertical fov degree. + */ + @NonNull + public Builder setVerticalFovDegrees( + @FloatRange(from = 0.0f, to = 180.0f, fromInclusive = false) + float verticalFovDegrees) { + mVerticalFovDegrees = verticalFovDegrees; + return this; + } + + /** + * Sets the frustum in near plane. + */ + @NonNull + public Builder setFrustumNearInWorldSpace( + @FloatRange(from = 0.0f) float frustumNearInWorldSpace) { + mFrustumNearInWorldSpace = frustumNearInWorldSpace; + return this; + } + + /** + * Sets the frustum in far plane. + */ + @NonNull + public Builder setFrustumFarInWorldSpace( + @FloatRange(from = 0.0f) float frustumFarInWorldSpace) { + mFrustumFarInWorldSpace = frustumFarInWorldSpace; + return this; + } + + /** + * Builds a new {@link CameraAttributes} instance. + */ + @NonNull + public CameraAttributes build() { + return new CameraAttributes(mAnchorPointInWorldSpace, + mAnchorPointInOutputUvSpace, + mCameraOrbitYawDegrees, + mCameraOrbitPitchDegrees, + mDollyDistanceInWorldSpace, + mVerticalFovDegrees, + mFrustumNearInWorldSpace, + mFrustumFarInWorldSpace); + } + } +} diff --git a/core/java/android/app/wallpapereffectsgeneration/CinematicEffectRequest.aidl b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectRequest.aidl new file mode 100644 index 0000000000000..234774645956a --- /dev/null +++ b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectRequest.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2022, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.wallpapereffectsgeneration; + +parcelable CinematicEffectRequest; \ No newline at end of file diff --git a/core/java/android/app/wallpapereffectsgeneration/CinematicEffectRequest.java b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectRequest.java new file mode 100644 index 0000000000000..f2e33131baa22 --- /dev/null +++ b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectRequest.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.wallpapereffectsgeneration; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.graphics.Bitmap; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * A {@link CinematicEffectRequest} is the data class having all the information + * passed to wallpaper effects generation service. + * + * @hide + */ +@SystemApi +public final class CinematicEffectRequest implements Parcelable { + /** + * Unique id of a cienmatic effect generation task. + */ + @NonNull + private String mTaskId; + + /** + * The bitmap to generate cinematic effect from. + */ + @NonNull + private Bitmap mBitmap; + + private CinematicEffectRequest(Parcel in) { + this.mTaskId = in.readString(); + this.mBitmap = Bitmap.CREATOR.createFromParcel(in); + } + + /** + * Constructor with task id and bitmap. + */ + public CinematicEffectRequest(@NonNull String taskId, @NonNull Bitmap bitmap) { + mTaskId = taskId; + mBitmap = bitmap; + } + + /** + * Returns the task id. + */ + @NonNull + public String getTaskId() { + return mTaskId; + } + + /** + * Returns the bitmap of this request. + */ + @NonNull + public Bitmap getBitmap() { + return mBitmap; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) { + return false; + } + CinematicEffectRequest that = (CinematicEffectRequest) o; + return mTaskId.equals(that.mTaskId); + } + + @Override + public int hashCode() { + return Objects.hash(mTaskId); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeString(mTaskId); + mBitmap.writeToParcel(out, flags); + } + + @NonNull + public static final Creator CREATOR = + new Creator() { + @Override + public CinematicEffectRequest createFromParcel(Parcel in) { + return new CinematicEffectRequest(in); + } + + @Override + public CinematicEffectRequest[] newArray(int size) { + return new CinematicEffectRequest[size]; + } + }; +} diff --git a/core/java/android/app/wallpapereffectsgeneration/CinematicEffectResponse.aidl b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectResponse.aidl new file mode 100644 index 0000000000000..1bd1e1e4bada5 --- /dev/null +++ b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectResponse.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2022, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package android.app.wallpapereffectsgeneration; + + parcelable CinematicEffectResponse; \ No newline at end of file diff --git a/core/java/android/app/wallpapereffectsgeneration/CinematicEffectResponse.java b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectResponse.java new file mode 100644 index 0000000000000..1254794964dd8 --- /dev/null +++ b/core/java/android/app/wallpapereffectsgeneration/CinematicEffectResponse.java @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.wallpapereffectsgeneration; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * A {@link CinematicEffectResponse} include textured meshes + * and camera attributes of key frames. + * + * @hide + */ +@SystemApi +public final class CinematicEffectResponse implements Parcelable { + /** @hide */ + @IntDef(prefix = {"CINEMATIC_EFFECT_STATUS_"}, + value = {CINEMATIC_EFFECT_STATUS_UNKNOWN, + CINEMATIC_EFFECT_STATUS_OK, + CINEMATIC_EFFECT_STATUS_ERROR, + CINEMATIC_EFFECT_STATUS_NOT_READY, + CINEMATIC_EFFECT_STATUS_PENDING, + CINEMATIC_EFFECT_STATUS_TOO_MANY_REQUESTS}) + @Retention(RetentionPolicy.SOURCE) + public @interface CinematicEffectStatusCode {} + + /** Cinematic effect generation unknown status. */ + public static final int CINEMATIC_EFFECT_STATUS_UNKNOWN = 0; + /** Cinematic effect generation success. */ + public static final int CINEMATIC_EFFECT_STATUS_OK = 1; + /** Cinematic effect generation failure. */ + public static final int CINEMATIC_EFFECT_STATUS_ERROR = 2; + /** Service not ready for cinematic effect generation. */ + public static final int CINEMATIC_EFFECT_STATUS_NOT_READY = 3; + /** Cienmatic effect generation process is pending. */ + public static final int CINEMATIC_EFFECT_STATUS_PENDING = 4; + /** Too manay requests for server to handle. */ + public static final int CINEMATIC_EFFECT_STATUS_TOO_MANY_REQUESTS = 5; + + /** @hide */ + @IntDef(prefix = {"IMAGE_CONTENT_TYPE_"}, + value = {IMAGE_CONTENT_TYPE_UNKNOWN, + IMAGE_CONTENT_TYPE_PEOPLE_PORTRAIT, + IMAGE_CONTENT_TYPE_LANDSCAPE, + IMAGE_CONTENT_TYPE_OTHER + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ImageContentType {} + + /** Image content unknown. */ + public static final int IMAGE_CONTENT_TYPE_UNKNOWN = 0; + /** Image content is people portrait. */ + public static final int IMAGE_CONTENT_TYPE_PEOPLE_PORTRAIT = 1; + /** Image content is landscape. */ + public static final int IMAGE_CONTENT_TYPE_LANDSCAPE = 2; + /** Image content is doesn't belong to other types. */ + public static final int IMAGE_CONTENT_TYPE_OTHER = 3; + + + @CinematicEffectStatusCode + private int mStatusCode; + + /** The id of the cinematic effect generation task. */ + @NonNull + private String mTaskId; + + @ImageContentType + private int mImageContentType; + + /** The textured mesh required to render cinematic effect. */ + @NonNull + private List mTexturedMeshes; + + /** The start camera position for animation. */ + @Nullable + private CameraAttributes mStartKeyFrame; + + /** The end camera position for animation. */ + @Nullable + private CameraAttributes mEndKeyFrame; + + private CinematicEffectResponse(Parcel in) { + mStatusCode = in.readInt(); + mTaskId = in.readString(); + mImageContentType = in.readInt(); + mTexturedMeshes = new ArrayList(); + in.readTypedList(mTexturedMeshes, TexturedMesh.CREATOR); + mStartKeyFrame = in.readTypedObject(CameraAttributes.CREATOR); + mEndKeyFrame = in.readTypedObject(CameraAttributes.CREATOR); + } + + private CinematicEffectResponse(@CinematicEffectStatusCode int statusCode, + String taskId, + @ImageContentType int imageContentType, + List texturedMeshes, + CameraAttributes startKeyFrame, + CameraAttributes endKeyFrame) { + mStatusCode = statusCode; + mTaskId = taskId; + mImageContentType = imageContentType; + mStartKeyFrame = startKeyFrame; + mEndKeyFrame = endKeyFrame; + mTexturedMeshes = texturedMeshes; + } + + /** Gets the cinematic effect generation status code. */ + @CinematicEffectStatusCode + public int getStatusCode() { + return mStatusCode; + } + + /** Get the task id. */ + @NonNull + public String getTaskId() { + return mTaskId; + } + + /** + * Get the image content type, which briefly classifies what's + * the content of image, like people portrait, landscape etc. + */ + @ImageContentType + public int getImageContentType() { + return mImageContentType; + } + + /** Get the textured meshes. */ + @NonNull + public List getTexturedMeshes() { + return mTexturedMeshes; + } + + /** + * Get the camera attributes (position info and other parameters, see docs of + * {@link CameraAttributes}) of the start key frame on the animation path. + */ + @Nullable + public CameraAttributes getStartKeyFrame() { + return mStartKeyFrame; + } + + /** + * Get the camera attributes (position info and other parameters, see docs of + * {@link CameraAttributes}) of the end key frame on the animation path. + */ + @Nullable + public CameraAttributes getEndKeyFrame() { + return mEndKeyFrame; + } + + @NonNull + public static final Creator CREATOR = + new Creator() { + @Override + public CinematicEffectResponse createFromParcel(Parcel in) { + return new CinematicEffectResponse(in); + } + + @Override + public CinematicEffectResponse[] newArray(int size) { + return new CinematicEffectResponse[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeInt(mStatusCode); + out.writeString(mTaskId); + out.writeInt(mImageContentType); + out.writeTypedList(mTexturedMeshes, flags); + out.writeTypedObject(mStartKeyFrame, flags); + out.writeTypedObject(mEndKeyFrame, flags); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) { + return false; + } + CinematicEffectResponse that = (CinematicEffectResponse) o; + return mTaskId.equals(that.mTaskId); + } + + @Override + public int hashCode() { + return Objects.hash(mTaskId); + } + /** + * Builder of {@link CinematicEffectResponse} + * + * @hide + */ + @SystemApi + public static final class Builder { + @CinematicEffectStatusCode + private int mStatusCode; + @NonNull + private String mTaskId; + @ImageContentType + private int mImageContentType; + @NonNull + private List mTexturedMeshes; + @Nullable + private CameraAttributes mStartKeyFrame; + @Nullable + private CameraAttributes mEndKeyFrame; + + /** + * Constructor with task id and status code. + * + * @hide + */ + @SystemApi + public Builder(@CinematicEffectStatusCode int statusCode, @NonNull String taskId) { + mStatusCode = statusCode; + mTaskId = taskId; + } + + /** + * Sets the image content type. + */ + @NonNull + public Builder setImageContentType(@ImageContentType int imageContentType) { + mImageContentType = imageContentType; + return this; + } + + + /** + * Sets the textured meshes. + */ + @NonNull + public Builder setTexturedMeshes(@NonNull List texturedMeshes) { + mTexturedMeshes = texturedMeshes; + return this; + } + + /** + * Sets start key frame. + */ + @NonNull + public Builder setStartKeyFrame(@Nullable CameraAttributes startKeyFrame) { + mStartKeyFrame = startKeyFrame; + return this; + } + + /** + * Sets end key frame. + */ + @NonNull + public Builder setEndKeyFrame(@Nullable CameraAttributes endKeyFrame) { + mEndKeyFrame = endKeyFrame; + return this; + } + + /** + * Builds a {@link CinematicEffectResponse} instance. + */ + @NonNull + public CinematicEffectResponse build() { + if (mTexturedMeshes == null) { + // Place holder because build doesn't allow list to be nullable. + mTexturedMeshes = new ArrayList<>(0); + } + return new CinematicEffectResponse(mStatusCode, mTaskId, mImageContentType, + mTexturedMeshes, mStartKeyFrame, mEndKeyFrame); + } + } +} diff --git a/core/java/android/app/wallpapereffectsgeneration/ICinematicEffectListener.aidl b/core/java/android/app/wallpapereffectsgeneration/ICinematicEffectListener.aidl new file mode 100644 index 0000000000000..c1a698d6be0ee --- /dev/null +++ b/core/java/android/app/wallpapereffectsgeneration/ICinematicEffectListener.aidl @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2022, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.wallpapereffectsgeneration; + +import android.app.wallpapereffectsgeneration.CinematicEffectResponse; + + +/** + * Callback used by system server to notify invoker of {@link WallpaperEffectsGenerationMAnager} + * of the cinematic effect generation result. + * + * @hide + */ +oneway interface ICinematicEffectListener { + void onCinematicEffectGenerated(in CinematicEffectResponse response); +} \ No newline at end of file diff --git a/core/java/android/app/wallpapereffectsgeneration/IWallpaperEffectsGenerationManager.aidl b/core/java/android/app/wallpapereffectsgeneration/IWallpaperEffectsGenerationManager.aidl new file mode 100644 index 0000000000000..706a89c043b9d --- /dev/null +++ b/core/java/android/app/wallpapereffectsgeneration/IWallpaperEffectsGenerationManager.aidl @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2022, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.wallpapereffectsgeneration; + +import android.app.wallpapereffectsgeneration.CinematicEffectRequest; +import android.app.wallpapereffectsgeneration.CinematicEffectResponse; +import android.app.wallpapereffectsgeneration.ICinematicEffectListener; + +/** + * Used by {@link android.app.wallpapereffectsgeneration.WallpaperEffectsGenerationManager} + * to to generate effects. + * + * @hide + */ +oneway interface IWallpaperEffectsGenerationManager { + void generateCinematicEffect(in CinematicEffectRequest request, + in ICinematicEffectListener listener); + + void returnCinematicEffectResponse(in CinematicEffectResponse response); +} \ No newline at end of file diff --git a/core/java/android/app/wallpapereffectsgeneration/TexturedMesh.java b/core/java/android/app/wallpapereffectsgeneration/TexturedMesh.java new file mode 100644 index 0000000000000..630de45e35061 --- /dev/null +++ b/core/java/android/app/wallpapereffectsgeneration/TexturedMesh.java @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.wallpapereffectsgeneration; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.graphics.Bitmap; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * The textured mesh representation, including a texture (bitmap) to sample from when rendering, + * and a mesh consisting of primitives such as triangles. The mesh is represented by an indices + * array describing the set of primitives in the mesh, and a vertices array that the indices + * refer to. + * + * @hide + */ +@SystemApi +public final class TexturedMesh implements Parcelable { + /** + * The texture to sample from when rendering mesh. + */ + @NonNull + private Bitmap mBitmap; + + /** + * The set of primitives as pointers into the vertices. + */ + @NonNull + private int[] mIndices; + + /** + * The specific vertices that the indices refer to. + */ + @NonNull + private float[] mVertices; + + /** @hide */ + @IntDef(prefix = {"INDICES_LAYOUT_"}, value = { + INDICES_LAYOUT_UNDEFINED, + INDICES_LAYOUT_TRIANGLES}) + @Retention(RetentionPolicy.SOURCE) + public @interface IndicesLayoutType { + } + + /** Undefined indices layout */ + public static final int INDICES_LAYOUT_UNDEFINED = 0; + /** + * Indices layout is triangle. Vertices are grouped into 3 and each + * group forms a triangle. + */ + public static final int INDICES_LAYOUT_TRIANGLES = 1; + + @IndicesLayoutType + private int mIndicesLayoutType; + + /** @hide */ + @IntDef(prefix = {"VERTICES_LAYOUT_"}, value = { + VERTICES_LAYOUT_UNDEFINED, + VERTICES_LAYOUT_POSITION3_UV2}) + @Retention(RetentionPolicy.SOURCE) + public @interface VerticesLayoutType { + } + + /** + * Undefined vertices layout. + */ + public static final int VERTICES_LAYOUT_UNDEFINED = 0; + /** + * The vertices array uses 5 numbers to represent a point, in the format + * of [x1, y1, z1, u1, v1, x2, y2, z2, u2, v2, ...]. + */ + public static final int VERTICES_LAYOUT_POSITION3_UV2 = 1; + + @VerticesLayoutType + private int mVerticesLayoutType; + + private TexturedMesh(Parcel in) { + this.mIndicesLayoutType = in.readInt(); + this.mVerticesLayoutType = in.readInt(); + this.mBitmap = in.readTypedObject(Bitmap.CREATOR); + Parcel data = Parcel.obtain(); + try { + byte[] bytes = in.readBlob(); + data.unmarshall(bytes, 0, bytes.length); + data.setDataPosition(0); + this.mIndices = data.createIntArray(); + this.mVertices = data.createFloatArray(); + } finally { + data.recycle(); + } + } + + private TexturedMesh(@NonNull Bitmap bitmap, @NonNull int[] indices, + @NonNull float[] vertices, @IndicesLayoutType int indicesLayoutType, + @VerticesLayoutType int verticesLayoutType) { + mBitmap = bitmap; + mIndices = indices; + mVertices = vertices; + mIndicesLayoutType = indicesLayoutType; + mVerticesLayoutType = verticesLayoutType; + } + + /** Get the bitmap, which is the texture to sample from when rendering. */ + @NonNull + public Bitmap getBitmap() { + return mBitmap; + } + + /** + * Get the indices as pointers to the vertices array. Depending on the getIndicesLayoutType(), + * the primitives may have different shapes. For example, with INDICES_LAYOUT_TRIANGLES, + * indices 0, 1, 2 forms a triangle, indices 3, 4, 5 form another triangle. + */ + @NonNull + public int[] getIndices() { + return mIndices; + } + + /** + * Get the vertices that the index array refers to. Depending on the getVerticesLayoutType() + * result, the vertices array can represent different per-vertex coordinates. For example, + * with VERTICES_LAYOUT_POSITION3_UV2 type, vertices are in the format of + * [x1, y1, z1, u1, v1, x2, y2, z2, u2, v2, ...]. + */ + @NonNull + public float[] getVertices() { + return mVertices; + } + + /** Get the indices layout type. */ + @IndicesLayoutType + @NonNull + public int getIndicesLayoutType() { + return mIndicesLayoutType; + } + + /** Get the indices layout type. */ + @VerticesLayoutType + @NonNull + public int getVerticesLayoutType() { + return mVerticesLayoutType; + } + + @NonNull + public static final Creator CREATOR = new Creator() { + @Override + public TexturedMesh createFromParcel(Parcel in) { + return new TexturedMesh(in); + } + + @Override + public TexturedMesh[] newArray(int size) { + return new TexturedMesh[size]; + } + }; + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeInt(mIndicesLayoutType); + out.writeInt(mVerticesLayoutType); + out.writeTypedObject(mBitmap, flags); + + // Indices and vertices can reach 5MB. Write the data as a Blob, + // which will be written to ashmem if too large. + Parcel data = Parcel.obtain(); + try { + data.writeIntArray(mIndices); + data.writeFloatArray(mVertices); + out.writeBlob(data.marshall()); + } finally { + data.recycle(); + } + } + + @Override + public int describeContents() { + return 0; + } + + /** + * A builder for {@link TexturedMesh} + * + * @hide + */ + @SystemApi + public static final class Builder { + private Bitmap mBitmap; + private int[] mIndices; + private float[] mVertices; + @IndicesLayoutType + private int mIndicesLayoutType; + @VerticesLayoutType + private int mVerticesLayouttype; + + /** + * Constructor with bitmap. + * + * @hide + */ + @SystemApi + public Builder(@NonNull Bitmap bitmap) { + mBitmap = bitmap; + } + + /** + * Set the required indices. The indices should represent the primitives. For example, + * with INDICES_LAYOUT_TRIANGLES, indices 0, 1, 2 forms a triangle, indices 3, 4, 5 + * form another triangle. + */ + @NonNull + public Builder setIndices(@NonNull int[] indices) { + mIndices = indices; + return this; + } + + /** + * Set the required vertices. The vertices array should represent per-vertex coordinates. + * For example, with VERTICES_LAYOUT_POSITION3_UV2 type, vertices are in the format of + * [x1, y1, z1, u1, v1, x2, y2, z2, u2, v2, ...]. + * + */ + @NonNull + public Builder setVertices(@NonNull float[] vertices) { + mVertices = vertices; + return this; + } + + /** + * Set the required indices layout type. + */ + @NonNull + public Builder setIndicesLayoutType(@IndicesLayoutType int indicesLayoutType) { + mIndicesLayoutType = indicesLayoutType; + return this; + } + + /** + * Set the required vertices layout type. + */ + @NonNull + public Builder setVerticesLayoutType(@VerticesLayoutType int verticesLayoutype) { + mVerticesLayouttype = verticesLayoutype; + return this; + } + + /** Builds a TexturedMesh based on the given parameters. */ + @NonNull + public TexturedMesh build() { + return new TexturedMesh(mBitmap, mIndices, mVertices, mIndicesLayoutType, + mVerticesLayouttype); + } + } +} diff --git a/core/java/android/app/wallpapereffectsgeneration/WallpaperEffectsGenerationManager.java b/core/java/android/app/wallpapereffectsgeneration/WallpaperEffectsGenerationManager.java new file mode 100644 index 0000000000000..5a1d27daa20b9 --- /dev/null +++ b/core/java/android/app/wallpapereffectsgeneration/WallpaperEffectsGenerationManager.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.wallpapereffectsgeneration; + +import android.annotation.CallbackExecutor; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.annotation.SystemService; +import android.content.Context; +import android.os.RemoteException; + +import java.util.concurrent.Executor; + +/** + * A {@link WallpaperEffectsGenerationManager} is the class that passes wallpaper effects + * generation requests to wallpaper effect generation service. For example, create a cinematic + * and render a cinematic live wallpaper with the response. + * + * Usage: + *
{@code
+ *      mWallpaperEffectsGenerationManager =
+ *          context.getSystemService(WallpaperEffectsGenerationManager.class);
+ *      mWallpaperEffectsGenerationManager.
+ *          generateCinematicEffect(cinematicEffectRequest, response->{
+ *              // proceed cinematic effect response.
+ *          });
+ * }
+ * + * @hide + */ +@SystemApi +@SystemService(Context.WALLPAPER_EFFECTS_GENERATION_SERVICE) +public final class WallpaperEffectsGenerationManager { + /** + * Interface for the cinematic effect listener. + */ + public interface CinematicEffectListener { + /** + * Async call when the cinematic effect response is generated. + * Client needs to check the status code of {@link CinematicEffectResponse} + * to determine if the effect generation is successful. + * + * @param response The generated cinematic effect response. + */ + void onCinematicEffectGenerated(@NonNull CinematicEffectResponse response); + } + + private final IWallpaperEffectsGenerationManager mService; + + /** @hide */ + public WallpaperEffectsGenerationManager( + @NonNull IWallpaperEffectsGenerationManager service) { + mService = service; + } + + /** + * Execute a {@link android.app.wallpapereffectsgeneration.CinematicEffectRequest} from + * the given parameters to the wallpaper effects generation service. After the cinematic + * effect response is ready, the given listener is invoked by the system with the response. + * The listener may never receive a callback if unexpected error happened when proceeding + * request. + * + * @param request request to generate cinematic effect. + * @param executor where the listener is invoked. + * @param listener listener invoked when the cinematic effect response is available. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION) + public void generateCinematicEffect(@NonNull CinematicEffectRequest request, + @NonNull @CallbackExecutor Executor executor, + @NonNull CinematicEffectListener listener) { + try { + mService.generateCinematicEffect(request, + new CinematicEffectListenerWrapper(listener, executor)); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + private static final class CinematicEffectListenerWrapper + extends ICinematicEffectListener.Stub { + @NonNull + private final CinematicEffectListener mListener; + @NonNull + private final Executor mExecutor; + + CinematicEffectListenerWrapper(@NonNull CinematicEffectListener listener, + @NonNull Executor executor) { + mListener = listener; + mExecutor = executor; + } + + @Override + public void onCinematicEffectGenerated(CinematicEffectResponse response) { + mExecutor.execute(() -> mListener.onCinematicEffectGenerated(response)); + } + } +} diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 4b4e00855ac1b..0ea869cbb03b7 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -5010,6 +5010,20 @@ public abstract class Context { */ public static final String SOUND_TRIGGER_MIDDLEWARE_SERVICE = "soundtrigger_middleware"; + /** + * Used for getting the wallpaper effects generation service. + * + *

NOTE: this service is optional; callers of + * {@code Context.getSystemServiceName(WALLPAPER_EFFECTS_GENERATION_SERVICE)} should check for + * {@code null}. + * + * @hide + * @see #getSystemService(String) + */ + @SystemApi + public static final String WALLPAPER_EFFECTS_GENERATION_SERVICE = + "wallpaper_effects_generation"; + /** * Used to access {@link MusicRecognitionManagerService}. * diff --git a/core/java/android/service/wallpapereffectsgeneration/IWallpaperEffectsGenerationService.aidl b/core/java/android/service/wallpapereffectsgeneration/IWallpaperEffectsGenerationService.aidl new file mode 100644 index 0000000000000..ca75d2ed35ed3 --- /dev/null +++ b/core/java/android/service/wallpapereffectsgeneration/IWallpaperEffectsGenerationService.aidl @@ -0,0 +1,28 @@ + +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.wallpapereffectsgeneration; + +import android.app.wallpapereffectsgeneration.CinematicEffectRequest; +/** + * Interface from the system to WallpaperEffectsGeneration service. + * + * @hide + */ +oneway interface IWallpaperEffectsGenerationService { + void onGenerateCinematicEffect(in CinematicEffectRequest request); +} \ No newline at end of file diff --git a/core/java/android/service/wallpapereffectsgeneration/WallpaperEffectsGenerationService.java b/core/java/android/service/wallpapereffectsgeneration/WallpaperEffectsGenerationService.java new file mode 100644 index 0000000000000..18b654ec8f04d --- /dev/null +++ b/core/java/android/service/wallpapereffectsgeneration/WallpaperEffectsGenerationService.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.wallpapereffectsgeneration; + +import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; + +import android.annotation.CallSuper; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.app.Service; +import android.app.wallpapereffectsgeneration.CinematicEffectRequest; +import android.app.wallpapereffectsgeneration.CinematicEffectResponse; +import android.app.wallpapereffectsgeneration.IWallpaperEffectsGenerationManager; +import android.content.Context; +import android.content.Intent; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Log; +import android.util.Slog; + +/** + * A service for handling wallpaper effects generation tasks. It must implement + * (onGenerateCinematicEffect} method to generate response and call returnCinematicEffectResponse + * to send the response. + * + *

To extend this service, you must declare the service in your manifest file with the + * {@link android.Manifest.permission#BIND_WALLPAPER_EFFECTS_GENERATION} permission and includes + * an intent filter with the {@link #SERVICE_INTERFACE} action. For example:

+ *
+ *     
+ *         
+ *             
+ *                 
+ *             
+ *         
+ *         
+ *     
+ * 
+ * + * @hide + */ +@SystemApi +public abstract class WallpaperEffectsGenerationService extends Service { + /** + * The {@link Intent} that must be declared as handled by the service. + * + *

The service must also require the + * {@link android.permission#MANAGE_WALLPAPER_EFFECTS_GENERATION} + * permission. + * + * @hide + */ + public static final String SERVICE_INTERFACE = + "android.service.wallpapereffectsgeneration.WallpaperEffectsGenerationService"; + private static final boolean DEBUG = false; + private static final String TAG = "WallpaperEffectsGenerationService"; + private Handler mHandler; + private IWallpaperEffectsGenerationManager mService; + + private final IWallpaperEffectsGenerationService mInterface = + new IWallpaperEffectsGenerationService.Stub() { + @Override + public void onGenerateCinematicEffect(CinematicEffectRequest request) { + mHandler.sendMessage( + obtainMessage( + WallpaperEffectsGenerationService::onGenerateCinematicEffect, + WallpaperEffectsGenerationService.this, request)); + } + }; + + /** + * Called when the OS receives a request for generating cinematic effect. On receiving the + * request, it extract cinematic information from the input and call + * {@link #returnCinematicEffectResponse} with the textured mesh + * and metadata wrapped in CinematicEffectResponse. + * + * @param request the cinematic effect request passed from the client. + */ + public abstract void onGenerateCinematicEffect(@NonNull CinematicEffectRequest request); + + /** + * Returns the cinematic effect response. Must be called when cinematic effect + * response is generated and ready to be sent back. Otherwise the response won't be + * returned. + * + * @param response the cinematic effect response returned from service provider. + */ + public final void returnCinematicEffectResponse(@NonNull CinematicEffectResponse response) { + try { + mService.returnCinematicEffectResponse(response); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @CallSuper + @Override + public void onCreate() { + super.onCreate(); + if (DEBUG) { + Log.d(TAG, "onCreate WallpaperEffectsGenerationService"); + } + mHandler = new Handler(Looper.getMainLooper(), null, true); + IBinder b = ServiceManager.getService(Context.WALLPAPER_EFFECTS_GENERATION_SERVICE); + mService = IWallpaperEffectsGenerationManager.Stub.asInterface(b); + } + + @NonNull + @Override + public final IBinder onBind(@NonNull Intent intent) { + if (DEBUG) { + Log.d(TAG, "onBind WallpaperEffectsGenerationService"); + } + if (SERVICE_INTERFACE.equals(intent.getAction())) { + return mInterface.asBinder(); + } + Slog.w(TAG, + "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + ": " + intent); + return null; + } +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index a0e426db0e103..80b8b9987266a 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -4162,6 +4162,16 @@ + + + + + + + diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 74cd519db1698..2f8994f3faedb 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4161,6 +4161,15 @@ + + +