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 com.android.providers.media.photopicker;
18 
19 import static android.provider.CloudMediaProviderContract.EXTRA_AUTHORITY;
20 import static android.provider.CloudMediaProviderContract.EXTRA_LOOPING_PLAYBACK_ENABLED;
21 import static android.provider.CloudMediaProviderContract.EXTRA_SURFACE_CONTROLLER_AUDIO_MUTE_ENABLED;
22 
23 import android.content.res.AssetFileDescriptor;
24 import android.database.Cursor;
25 import android.graphics.Point;
26 import android.os.Bundle;
27 import android.os.CancellationSignal;
28 import android.os.ParcelFileDescriptor;
29 import android.os.RemoteException;
30 import android.provider.CloudMediaProvider;
31 import android.provider.ICloudMediaSurfaceController;
32 import android.util.Log;
33 import android.view.Surface;
34 
35 import androidx.annotation.NonNull;
36 import androidx.annotation.Nullable;
37 
38 import com.android.providers.media.photopicker.ui.remotepreview.RemoteSurfaceController;
39 
40 import java.io.FileNotFoundException;
41 
42 /**
43  * Implements the {@link CloudMediaProvider} interface over the local items in the MediaProvider
44  * database.
45  */
46 public class RemoteVideoPreviewProvider extends CloudMediaProvider {
47     private static final String TAG = "RemoteVideoPreviewProvider";
48     public static final String AUTHORITY =
49             "com.android.providers.media.remote_video_preview";
50 
51     @Override
onCreate()52     public boolean onCreate() {
53         return true;
54     }
55 
56     @Override
onQueryMedia(Bundle extras)57     public Cursor onQueryMedia(Bundle extras) {
58         throw new UnsupportedOperationException("onQueryMedia not supported");
59     }
60 
61     @Override
onQueryDeletedMedia(Bundle extras)62     public Cursor onQueryDeletedMedia(Bundle extras) {
63         throw new UnsupportedOperationException("onQueryDeletedMedia not supported");
64     }
65 
66     @Override
onOpenPreview(String mediaId, Point size, Bundle extras, CancellationSignal signal)67     public AssetFileDescriptor onOpenPreview(String mediaId, Point size, Bundle extras,
68             CancellationSignal signal) throws FileNotFoundException {
69         throw new UnsupportedOperationException("onOpenPreview not supported");
70     }
71 
72     @Override
onOpenMedia(String mediaId, Bundle extras, CancellationSignal signal)73     public ParcelFileDescriptor onOpenMedia(String mediaId, Bundle extras,
74             CancellationSignal signal) throws FileNotFoundException {
75         throw new UnsupportedOperationException("onOpenMedia not supported");
76     }
77 
78     @Override
onGetMediaCollectionInfo(Bundle extras)79     public Bundle onGetMediaCollectionInfo(Bundle extras) {
80         throw new UnsupportedOperationException("onGetMediaCollectionInfo not supported");
81     }
82 
83     @Override
84     @Nullable
onCreateCloudMediaSurfaceController(@onNull Bundle config, CloudMediaSurfaceStateChangedCallback callback)85     public CloudMediaSurfaceController onCreateCloudMediaSurfaceController(@NonNull Bundle config,
86             CloudMediaSurfaceStateChangedCallback callback) {
87         final String authority = config.getString(EXTRA_AUTHORITY);
88         if (authority == null) {
89             throw new IllegalArgumentException("No cloud provider authority available");
90         }
91 
92         final boolean enableLoop = config.getBoolean(EXTRA_LOOPING_PLAYBACK_ENABLED, false);
93         final boolean muteAudio = config.getBoolean(EXTRA_SURFACE_CONTROLLER_AUDIO_MUTE_ENABLED,
94                 false);
95         return new RemoteSurfaceController(getContext(), authority, enableLoop, muteAudio,
96                 callback);
97     }
98 
99     /**
100      * {@link CloudMediaSurfaceController} implementation that proxies all requests to a 'remote'
101      * {@link RemoteSurfaceController}.
102      */
103     public static class SurfaceControllerProxy extends CloudMediaSurfaceController {
104         private final ICloudMediaSurfaceController mController;
105 
SurfaceControllerProxy(ICloudMediaSurfaceController controller)106         public SurfaceControllerProxy(ICloudMediaSurfaceController controller) {
107             mController = controller;
108         }
109 
110         @Override
onPlayerCreate()111         public void onPlayerCreate() {
112             try {
113                 mController.onPlayerCreate();
114             } catch (RemoteException e) {
115                 Log.e(TAG, "onPlayerCreate failed", e);
116             }
117         }
118 
119         @Override
onPlayerRelease()120         public void onPlayerRelease() {
121             try {
122                 mController.onPlayerRelease();
123             } catch (RemoteException e) {
124                 Log.e(TAG, "onPlayerRelease failed", e);
125             }
126         }
127 
128         @Override
onSurfaceCreated(int surfaceId, @NonNull Surface surface, @NonNull String mediaId)129         public void onSurfaceCreated(int surfaceId, @NonNull Surface surface,
130                 @NonNull String mediaId) {
131             try {
132                 mController.onSurfaceCreated(surfaceId, surface, mediaId);
133             } catch (RemoteException e) {
134                 Log.e(TAG, "onSurfaceCreated failed", e);
135             }
136         }
137 
138         @Override
onSurfaceChanged(int surfaceId, int format, int width, int height)139         public void onSurfaceChanged(int surfaceId, int format, int width, int height) {
140             try {
141                 mController.onSurfaceChanged(surfaceId, format, width, height);
142             } catch (RemoteException e) {
143                 Log.e(TAG, "onSurfaceChanged failed", e);
144             }
145         }
146 
147         @Override
onSurfaceDestroyed(int surfaceId)148         public void onSurfaceDestroyed(int surfaceId) {
149             try {
150                 mController.onSurfaceDestroyed(surfaceId);
151             } catch (RemoteException e) {
152                 Log.e(TAG, "onSurfaceDestroyed failed", e);
153             }
154         }
155 
156         @Override
onMediaPlay(int surfaceId)157         public void onMediaPlay(int surfaceId) {
158             try {
159                 mController.onMediaPlay(surfaceId);
160             } catch (RemoteException e) {
161                 Log.e(TAG, "onMediaPlay failed", e);
162             }
163         }
164 
165         @Override
onMediaPause(int surfaceId)166         public void onMediaPause(int surfaceId) {
167             try {
168                 mController.onMediaPause(surfaceId);
169             } catch (RemoteException e) {
170                 Log.e(TAG, "onMediaPause failed", e);
171             }
172         }
173 
174         @Override
onMediaSeekTo(int surfaceId, long timestampMillis)175         public void onMediaSeekTo(int surfaceId, long timestampMillis) {
176             try {
177                 mController.onMediaSeekTo(surfaceId, timestampMillis);
178             } catch (RemoteException e) {
179                 Log.e(TAG, "onMediaSeekTo failed", e);
180             }
181         }
182 
183         @Override
onConfigChange(@onNull Bundle config)184         public void onConfigChange(@NonNull Bundle config) {
185             try {
186                 mController.onConfigChange(config);
187             } catch (RemoteException e) {
188                 Log.e(TAG, "onConfigChange failed", e);
189             }
190         }
191 
192         @Override
onDestroy()193         public void onDestroy() {
194             try {
195                 mController.onDestroy();
196             } catch (RemoteException e) {
197                 Log.e(TAG, "onDestroy failed", e);
198             }
199         }
200     }
201 }
202