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