1 /*
2  * Copyright (C) 2024 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.provider;
18 
19 import static java.lang.annotation.RetentionPolicy.SOURCE;
20 
21 import android.annotation.FlaggedApi;
22 import android.annotation.NonNull;
23 import android.annotation.SystemApi;
24 import android.app.Service;
25 import android.content.Intent;
26 import android.os.CancellationSignal;
27 import android.os.IBinder;
28 import android.provider.mediacognitionutils.GetProcessingVersionsCallbackImpl;
29 import android.provider.mediacognitionutils.ICognitionGetVersionsCallbackInternal;
30 import android.provider.mediacognitionutils.ICognitionProcessMediaCallbackInternal;
31 import android.provider.mediacognitionutils.IMediaCognitionService;
32 import android.provider.mediacognitionutils.ProcessMediaCallbackImpl;
33 import android.util.Log;
34 
35 import androidx.annotation.IntDef;
36 import androidx.annotation.Nullable;
37 
38 import com.android.providers.media.flags.Flags;
39 
40 import java.lang.annotation.Retention;
41 import java.util.List;
42 
43 
44 /**
45  * <p> Base class for a service which can be implemented by privileged APKs.
46  * This service gets request only from {@link com.android.providers.media.MediaProvider} to extract
47  * data from media using various smart processing like image ocr, image labeling, etc. </p>
48  *
49  * <p>
50  * <h3>Manifest entry</h3>
51  * <p>MediaCognitionService must require the permission
52  * "com.android.providers.media.permission.BIND_MEDIA_COGNITION_SERVICE". </p>
53  *
54  * <pre class="prettyprint">
55  * {@literal
56  * <service
57  *     android:name=".MyMediaCognitionService"
58  *     android:exported="true"
59  *     android:permission="com.android.providers.media.permission.BIND_MEDIA_COGNITION_SERVICE">
60  *     <intent-filter>
61  *         <action android:name="android.provider.MediaCognitionService" />
62  *         <category android:name="android.intent.category.DEFAULT"/>
63  *     </intent-filter>
64  * </service>}
65  * </pre>
66  * </p>
67  *
68  * Only one instance of MediaCognitionService will be in function at a time.
69  * OEMs can specify the default MediaCognitionService through runtime resource overlay,
70  * by setting value of the resource {@code config_default_media_cognition_service_package}.
71  * The overlayable subset which has this resource is {@code MediaProviderConfig}
72  *
73  * @hide
74  */
75 @SystemApi
76 @FlaggedApi(Flags.FLAG_MEDIA_COGNITION_SERVICE)
77 public abstract class MediaCognitionService extends Service {
78 
79     /**
80      * @hide
81      */
82     public static final String TAG = "MediaCognitionService";
83 
84     public static final String SERVICE_INTERFACE = "android.provider.MediaCognitionService";
85 
86     /**
87      * Permission required to protect {@link MediaCognitionService} instances. Implementation should
88      * require this in the {@code permission} attribute in their {@code <service>} tag.
89      * The OS will not bind to a service without this protection.
90      */
91     public static final String BIND_MEDIA_COGNITION_SERVICE =
92             "com.android.providers.media.permission.BIND_MEDIA_COGNITION_SERVICE";
93 
94     /**
95      * This contains variables representing different processing types that
96      * MediaProvider can request the service.
97      */
98     public interface ProcessingTypes {
99         /**
100          * Variable for representing processing of image ocr of latin script.
101          */
102         public static final int IMAGE_OCR_LATIN = 1 << 0;
103 
104         /**
105          * Variable for representing processing of image labeling.
106          */
107         public static final int IMAGE_LABEL = 1 << 1;
108     }
109 
110     /**
111      * IntDef for bitmasks of ProcessingTypes
112      * @hide
113      */
114     @IntDef(flag = true, value = {ProcessingTypes.IMAGE_OCR_LATIN,
115             ProcessingTypes.IMAGE_LABEL})
116     @Retention(SOURCE)
117     public @interface ProcessingCombination {
118     }
119 
120     /**
121      * IntDef for the values in ProcessingTypes. No bitmask.
122      * @hide
123      */
124     @IntDef(value = {ProcessingTypes.IMAGE_OCR_LATIN,
125             ProcessingTypes.IMAGE_LABEL})
126     @Retention(SOURCE)
127     public @interface ProcessingType {
128     }
129 
130     @Override
131     @Nullable
onBind(@ullable Intent intent)132     public final IBinder onBind(@Nullable Intent intent) {
133         if (!SERVICE_INTERFACE.equals(intent.getAction())) {
134             Log.w(TAG, "Wrong action");
135             return null;
136         }
137         return mInterface.asBinder();
138     }
139 
140     /**
141      * <p> Implement this to process media for different cognition processing. Return the results
142      * through the callback. For every {@link MediaCognitionProcessingRequest} prepare a
143      * {@link MediaCognitionProcessingResponse} and return list of responses
144      * through the callback function: {@link MediaCognitionProcessingCallback#onSuccess(List)}.
145      * The responses must be returned all at once, for all the requests given.
146      * If one of the request could not be processed, add an empty response for that specific request
147      * in the returned responses.
148      * </p>
149      * <p> Each MediaCognitionProcessingRequest object contains a checker function
150      * {@link MediaCognitionProcessingRequest#checkProcessingRequired(int)} in which you can pass any
151      * processing type from the available ones here: {@link ProcessingTypes}.
152      * If the request requires a processing include the result
153      * in {@link MediaCognitionProcessingResponse}.
154      * </p>
155      *
156      *
157      *
158      * <p> There is a time limit to respond to the callback.
159      * Callback must be responded within less than 5 minutes.</p>
160      *
161      * @param requests           List of {@link MediaCognitionProcessingRequest}
162      * @param cancellationSignal Signal to attach a listener to, and receive cancellation signals
163      *                           from the client.
164      * @param callback           Callback for giving the result
165      */
onProcessMedia(@onNull List<MediaCognitionProcessingRequest> requests, @Nullable CancellationSignal cancellationSignal, @NonNull MediaCognitionProcessingCallback callback)166     public abstract void onProcessMedia(@NonNull List<MediaCognitionProcessingRequest> requests,
167             @Nullable CancellationSignal cancellationSignal,
168             @NonNull MediaCognitionProcessingCallback callback);
169 
170     /**
171      * <p>Implement this to return version of all processing types.
172      * This will be used by MediaProvider to assess if reprocessing is required,
173      * once the version changes. </p>
174      *
175      * <p>Set versions of each processing types available here: {@link ProcessingTypes}.
176      * The result need to be composed using {@link MediaCognitionProcessingVersions}.
177      * Return the result via the callback function:
178      * {@link MediaCognitionGetVersionsCallback#onSuccess(MediaCognitionProcessingVersions)}
179      * </p>
180      *
181      * <p> There is a time limit to respond to the callback.
182      * Callback must be responded within less than 5 minutes.</p>
183      *
184      */
onGetProcessingVersions( @onNull MediaCognitionGetVersionsCallback callback)185     public abstract void onGetProcessingVersions(
186             @NonNull MediaCognitionGetVersionsCallback callback);
187 
188 
189     private final IMediaCognitionService mInterface = new IMediaCognitionService.Stub() {
190         @Override
191         public void processMedia(List<MediaCognitionProcessingRequest> requests,
192                 ICognitionProcessMediaCallbackInternal binderCallback) {
193             onProcessMedia(requests, null, new ProcessMediaCallbackImpl(binderCallback));
194         }
195 
196         @Override
197         public void getProcessingVersions(ICognitionGetVersionsCallbackInternal binderCallback) {
198             onGetProcessingVersions(new GetProcessingVersionsCallbackImpl(binderCallback));
199         }
200     };
201 
202 }
203