1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.service.wallpapereffectsgeneration;
18 
19 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
20 
21 import android.annotation.CallSuper;
22 import android.annotation.MainThread;
23 import android.annotation.NonNull;
24 import android.annotation.SystemApi;
25 import android.app.Service;
26 import android.app.wallpapereffectsgeneration.CinematicEffectRequest;
27 import android.app.wallpapereffectsgeneration.CinematicEffectResponse;
28 import android.app.wallpapereffectsgeneration.IWallpaperEffectsGenerationManager;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.os.Handler;
32 import android.os.IBinder;
33 import android.os.Looper;
34 import android.os.RemoteException;
35 import android.os.ServiceManager;
36 import android.util.Log;
37 import android.util.Slog;
38 
39 /**
40  * A service for handling wallpaper effects generation tasks. It must implement
41  * (onGenerateCinematicEffect} method to generate response and call returnCinematicEffectResponse
42  * to send the response.
43  *
44  * <p>To extend this service, you must declare the service in your manifest file with the
45  * {@link android.Manifest.permission#BIND_WALLPAPER_EFFECTS_GENERATION} permission and includes
46  * an intent filter with the {@link #SERVICE_INTERFACE} action. For example: </p>
47  * <pre>
48  *     <application>
49  *         <service android:name=".CtsWallpaperEffectsGenerationService"
50  *             android:exported="true"
51  *             android:label="CtsWallpaperEffectsGenerationService"
52  *             android:permission="android.permission.BIND_WALLPAPER_EFFECTS_GENERATION_SERVICE">
53  *             <intent-filter>
54  *                 <action android:name="android.service.wallpapereffectsgeneration.WallpaperEffectsGenerationService"
55  />
56  *             </intent-filter>
57  *         </service>
58  *         <uses-library android:name="android.test.runner"/>
59  *     </application>
60  * </pre>
61  *
62  * @hide
63  */
64 @SystemApi
65 public abstract class WallpaperEffectsGenerationService extends Service {
66     /**
67      * The {@link Intent} that must be declared as handled by the service.
68      *
69      * <p>The service must also require the
70      * {@link android.permission#MANAGE_WALLPAPER_EFFECTS_GENERATION}
71      * permission.
72      *
73      */
74     public static final String SERVICE_INTERFACE =
75             "android.service.wallpapereffectsgeneration.WallpaperEffectsGenerationService";
76     private static final boolean DEBUG = false;
77     private static final String TAG = "WallpaperEffectsGenerationService";
78     private Handler mHandler;
79     private IWallpaperEffectsGenerationManager mService;
80 
81     private final IWallpaperEffectsGenerationService  mInterface =
82             new IWallpaperEffectsGenerationService.Stub() {
83                 @Override
84                 public void onGenerateCinematicEffect(CinematicEffectRequest request) {
85                     mHandler.sendMessage(
86                             obtainMessage(
87                                     WallpaperEffectsGenerationService::onGenerateCinematicEffect,
88                                     WallpaperEffectsGenerationService.this, request));
89                 }
90             };
91 
92     /**
93      * Called when the OS receives a request for generating cinematic effect. On receiving the
94      * request, it extract cinematic information from the input and call
95      * {@link #returnCinematicEffectResponse} with the textured mesh
96      * and metadata wrapped in CinematicEffectResponse.
97      *
98      * @param request the cinematic effect request passed from the client.
99      */
100     @MainThread
onGenerateCinematicEffect(@onNull CinematicEffectRequest request)101     public abstract void onGenerateCinematicEffect(@NonNull CinematicEffectRequest request);
102 
103     /**
104      * Returns the cinematic effect response. Must be called when cinematic effect
105      * response is generated and ready to be sent back. Otherwise the response won't be
106      * returned.
107      *
108      * @param response the cinematic effect response returned from service provider.
109      */
returnCinematicEffectResponse(@onNull CinematicEffectResponse response)110     public final void returnCinematicEffectResponse(@NonNull CinematicEffectResponse response) {
111         try {
112             mService.returnCinematicEffectResponse(response);
113         } catch (RemoteException e) {
114             throw e.rethrowFromSystemServer();
115         }
116     }
117 
118     @CallSuper
119     @Override
onCreate()120     public void onCreate() {
121         super.onCreate();
122         if (DEBUG) {
123             Log.d(TAG, "onCreate WallpaperEffectsGenerationService");
124         }
125         mHandler = new Handler(Looper.getMainLooper(), null, true);
126         IBinder b = ServiceManager.getService(Context.WALLPAPER_EFFECTS_GENERATION_SERVICE);
127         mService = IWallpaperEffectsGenerationManager.Stub.asInterface(b);
128     }
129 
130     @NonNull
131     @Override
onBind(@onNull Intent intent)132     public final IBinder onBind(@NonNull Intent intent) {
133         if (DEBUG) {
134             Log.d(TAG, "onBind WallpaperEffectsGenerationService");
135         }
136         if (SERVICE_INTERFACE.equals(intent.getAction())) {
137             return mInterface.asBinder();
138         }
139         Slog.w(TAG,
140                 "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + ": " + intent);
141         return null;
142     }
143 }
144