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.photopicker.cts.cloudproviders;
18 
19 import static android.photopicker.cts.PickerProviderMediaGenerator.MediaGenerator;
20 import static android.photopicker.cts.PickerProviderMediaGenerator.QueryExtras;
21 import static android.provider.CloudMediaProviderContract.EXTRA_LOOPING_PLAYBACK_ENABLED;
22 
23 import static org.mockito.Mockito.mock;
24 
25 import android.content.Context;
26 import android.content.res.AssetFileDescriptor;
27 import android.database.Cursor;
28 import android.graphics.Point;
29 import android.os.Bundle;
30 import android.os.CancellationSignal;
31 import android.os.ParcelFileDescriptor;
32 import android.photopicker.cts.PickerProviderMediaGenerator;
33 import android.provider.CloudMediaProvider;
34 import android.util.Log;
35 import android.view.Surface;
36 
37 import androidx.annotation.NonNull;
38 
39 import java.io.FileNotFoundException;
40 
41 /**
42  * Implements a cloud {@link CloudMediaProvider} interface over items generated with
43  * {@link MediaGenerator}.
44  */
45 public class CloudProviderPrimary extends CloudMediaProvider {
46     public static final String AUTHORITY = "android.photopicker.cts.cloudproviders.cloud_primary";
47 
48     private static final String TAG = "CloudProviderPrimary";
49     private static final CloudMediaSurfaceControllerImpl sMockSurfaceControllerListener =
50             mock(CloudMediaSurfaceControllerImpl.class);
51 
52     private static CloudMediaSurfaceControllerImpl sSurfaceControllerImpl = null;
53 
54     private MediaGenerator mMediaGenerator;
55 
56     @Override
onCreate()57     public boolean onCreate() {
58         mMediaGenerator = PickerProviderMediaGenerator.getMediaGenerator(getContext(), AUTHORITY);
59 
60         return true;
61     }
62 
63     @Override
onQueryMedia(Bundle extras)64     public Cursor onQueryMedia(Bundle extras) {
65         final QueryExtras queryExtras = new QueryExtras(extras);
66 
67         return mMediaGenerator.getMedia(queryExtras.generation, queryExtras.albumId,
68                 queryExtras.mimeType, queryExtras.sizeBytes, queryExtras.pageSize);
69     }
70 
71     @Override
onQueryDeletedMedia(Bundle extras)72     public Cursor onQueryDeletedMedia(Bundle extras) {
73         final QueryExtras queryExtras = new QueryExtras(extras);
74 
75         return mMediaGenerator.getDeletedMedia(queryExtras.generation);
76     }
77 
78     @Override
onQueryAlbums(Bundle extras)79     public Cursor onQueryAlbums(Bundle extras) {
80         final QueryExtras queryExtras = new QueryExtras(extras);
81 
82         return mMediaGenerator.getAlbums(queryExtras.mimeType, queryExtras.sizeBytes);
83     }
84 
85     @Override
onOpenPreview(String mediaId, Point size, Bundle extras, CancellationSignal signal)86     public AssetFileDescriptor onOpenPreview(String mediaId, Point size, Bundle extras,
87             CancellationSignal signal) throws FileNotFoundException {
88         return new AssetFileDescriptor(mMediaGenerator.openMedia(mediaId), 0,
89                 AssetFileDescriptor.UNKNOWN_LENGTH);
90     }
91 
92     @Override
onOpenMedia(String mediaId, Bundle extras, CancellationSignal signal)93     public ParcelFileDescriptor onOpenMedia(String mediaId, Bundle extras,
94             CancellationSignal signal) throws FileNotFoundException {
95         return mMediaGenerator.openMedia(mediaId);
96     }
97 
98     @Override
onGetMediaCollectionInfo(Bundle extras)99     public Bundle onGetMediaCollectionInfo(Bundle extras) {
100         return mMediaGenerator.getMediaCollectionInfo();
101     }
102 
103     @Override
onCreateCloudMediaSurfaceController(@onNull Bundle config, @NonNull CloudMediaSurfaceStateChangedCallback callback)104     public CloudMediaSurfaceController onCreateCloudMediaSurfaceController(@NonNull Bundle config,
105             @NonNull CloudMediaSurfaceStateChangedCallback callback) {
106         final boolean enableLoop = config.getBoolean(EXTRA_LOOPING_PLAYBACK_ENABLED, false);
107         sSurfaceControllerImpl =
108                 new CloudMediaSurfaceControllerImpl(getContext(), enableLoop, callback);
109         return sSurfaceControllerImpl;
110     }
111 
112     /**
113      * @return mock {@link CloudMediaSurfaceController} that enables us to test API calls from
114      * PhotoPicker to the {@link CloudMediaProvider}.
115      */
getMockSurfaceControllerListener()116     public static CloudMediaSurfaceControllerImpl getMockSurfaceControllerListener() {
117         return sMockSurfaceControllerListener;
118     }
119 
setPlaybackState(int surfaceId, int state)120     public static void setPlaybackState(int surfaceId, int state) {
121         if (sSurfaceControllerImpl == null) {
122             throw new IllegalStateException("Surface Controller object expected to be not null");
123         }
124 
125         sSurfaceControllerImpl.sendPlaybackEvent(surfaceId, state);
126     }
127 
128     public static class CloudMediaSurfaceControllerImpl extends CloudMediaSurfaceController {
129 
130         private final CloudMediaSurfaceStateChangedCallback mCallback;
131 
CloudMediaSurfaceControllerImpl(Context context, boolean enableLoop, CloudMediaSurfaceStateChangedCallback callback)132         CloudMediaSurfaceControllerImpl(Context context, boolean enableLoop,
133                 CloudMediaSurfaceStateChangedCallback callback) {
134             mCallback = callback;
135             Log.d(TAG, "Surface controller created.");
136         }
137 
138         @Override
onPlayerCreate()139         public void onPlayerCreate() {
140             sMockSurfaceControllerListener.onPlayerCreate();
141             Log.d(TAG, "Player created.");
142         }
143 
144         @Override
onPlayerRelease()145         public void onPlayerRelease() {
146             sMockSurfaceControllerListener.onPlayerRelease();
147             Log.d(TAG, "Player released.");
148         }
149 
150         @Override
onSurfaceCreated(int surfaceId, @NonNull Surface surface, @NonNull String mediaId)151         public void onSurfaceCreated(int surfaceId, @NonNull Surface surface,
152                 @NonNull String mediaId) {
153             sMockSurfaceControllerListener.onSurfaceCreated(surfaceId, surface, mediaId);
154 
155             Log.d(TAG, "Surface prepared: " + surfaceId + ". Surface: " + surface
156                     + ". MediaId: " + mediaId);
157         }
158 
159         @Override
onSurfaceChanged(int surfaceId, int format, int width, int height)160         public void onSurfaceChanged(int surfaceId, int format, int width, int height) {
161             sMockSurfaceControllerListener.onSurfaceChanged(surfaceId, format, width, height);
162             Log.d(TAG, "Surface changed: " + surfaceId + ". Format: " + format + ". Width: "
163                     + width + ". Height: " + height);
164         }
165 
166         @Override
onSurfaceDestroyed(int surfaceId)167         public void onSurfaceDestroyed(int surfaceId) {
168             sMockSurfaceControllerListener.onSurfaceDestroyed(surfaceId);
169             Log.d(TAG, "onSurfaceDestroyed: " + surfaceId);
170         }
171 
172         @Override
onMediaPlay(int surfaceId)173         public void onMediaPlay(int surfaceId) {
174             sMockSurfaceControllerListener.onMediaPlay(surfaceId);
175             Log.d(TAG, "onMediaPlay: " + surfaceId);
176         }
177 
178         @Override
onMediaPause(int surfaceId)179         public void onMediaPause(int surfaceId) {
180             sMockSurfaceControllerListener.onMediaPause(surfaceId);
181             Log.d(TAG, "onMediaPause: " + surfaceId);
182         }
183 
184         @Override
onMediaSeekTo(int surfaceId, long timestampMillis)185         public void onMediaSeekTo(int surfaceId, long timestampMillis) {
186             sMockSurfaceControllerListener.onMediaSeekTo(surfaceId, timestampMillis);
187             Log.d(TAG, "Media seeked: " + surfaceId + ". Timestamp: " + timestampMillis);
188         }
189 
190         @Override
onConfigChange(@onNull Bundle config)191         public void onConfigChange(@NonNull Bundle config) {
192             sMockSurfaceControllerListener.onConfigChange(config);
193             Log.d(TAG, "onConfigChange config: " + config);
194         }
195 
196         @Override
onDestroy()197         public void onDestroy() {
198             sMockSurfaceControllerListener.onDestroy();
199             Log.d(TAG, "Surface controller destroyed.");
200         }
201 
sendPlaybackEvent(int surfaceId, int state)202         public void sendPlaybackEvent(int surfaceId, int state) {
203             mCallback.setPlaybackState(surfaceId, state, null);
204         }
205     }
206 }
207