/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.photopicker.cts.cloudproviders; import static android.photopicker.cts.PickerProviderMediaGenerator.MediaGenerator; import static android.photopicker.cts.PickerProviderMediaGenerator.QueryExtras; import static android.provider.CloudMediaProviderContract.EXTRA_LOOPING_PLAYBACK_ENABLED; import static org.mockito.Mockito.mock; import android.content.Context; import android.content.res.AssetFileDescriptor; import android.database.Cursor; import android.graphics.Point; import android.os.Bundle; import android.os.CancellationSignal; import android.os.ParcelFileDescriptor; import android.photopicker.cts.PickerProviderMediaGenerator; import android.provider.CloudMediaProvider; import android.util.Log; import android.view.Surface; import androidx.annotation.NonNull; import java.io.FileNotFoundException; /** * Implements a cloud {@link CloudMediaProvider} interface over items generated with * {@link MediaGenerator}. */ public class CloudProviderPrimary extends CloudMediaProvider { public static final String AUTHORITY = "android.photopicker.cts.cloudproviders.cloud_primary"; private static final String TAG = "CloudProviderPrimary"; private static final CloudMediaSurfaceControllerImpl sMockSurfaceControllerListener = mock(CloudMediaSurfaceControllerImpl.class); private static CloudMediaSurfaceControllerImpl sSurfaceControllerImpl = null; private MediaGenerator mMediaGenerator; @Override public boolean onCreate() { mMediaGenerator = PickerProviderMediaGenerator.getMediaGenerator(getContext(), AUTHORITY); return true; } @Override public Cursor onQueryMedia(Bundle extras) { final QueryExtras queryExtras = new QueryExtras(extras); return mMediaGenerator.getMedia(queryExtras.generation, queryExtras.albumId, queryExtras.mimeType, queryExtras.sizeBytes, queryExtras.pageSize); } @Override public Cursor onQueryDeletedMedia(Bundle extras) { final QueryExtras queryExtras = new QueryExtras(extras); return mMediaGenerator.getDeletedMedia(queryExtras.generation); } @Override public Cursor onQueryAlbums(Bundle extras) { final QueryExtras queryExtras = new QueryExtras(extras); return mMediaGenerator.getAlbums(queryExtras.mimeType, queryExtras.sizeBytes); } @Override public AssetFileDescriptor onOpenPreview(String mediaId, Point size, Bundle extras, CancellationSignal signal) throws FileNotFoundException { return new AssetFileDescriptor(mMediaGenerator.openMedia(mediaId), 0, AssetFileDescriptor.UNKNOWN_LENGTH); } @Override public ParcelFileDescriptor onOpenMedia(String mediaId, Bundle extras, CancellationSignal signal) throws FileNotFoundException { return mMediaGenerator.openMedia(mediaId); } @Override public Bundle onGetMediaCollectionInfo(Bundle extras) { return mMediaGenerator.getMediaCollectionInfo(); } @Override public CloudMediaSurfaceController onCreateCloudMediaSurfaceController(@NonNull Bundle config, @NonNull CloudMediaSurfaceStateChangedCallback callback) { final boolean enableLoop = config.getBoolean(EXTRA_LOOPING_PLAYBACK_ENABLED, false); sSurfaceControllerImpl = new CloudMediaSurfaceControllerImpl(getContext(), enableLoop, callback); return sSurfaceControllerImpl; } /** * @return mock {@link CloudMediaSurfaceController} that enables us to test API calls from * PhotoPicker to the {@link CloudMediaProvider}. */ public static CloudMediaSurfaceControllerImpl getMockSurfaceControllerListener() { return sMockSurfaceControllerListener; } public static void setPlaybackState(int surfaceId, int state) { if (sSurfaceControllerImpl == null) { throw new IllegalStateException("Surface Controller object expected to be not null"); } sSurfaceControllerImpl.sendPlaybackEvent(surfaceId, state); } public static class CloudMediaSurfaceControllerImpl extends CloudMediaSurfaceController { private final CloudMediaSurfaceStateChangedCallback mCallback; CloudMediaSurfaceControllerImpl(Context context, boolean enableLoop, CloudMediaSurfaceStateChangedCallback callback) { mCallback = callback; Log.d(TAG, "Surface controller created."); } @Override public void onPlayerCreate() { sMockSurfaceControllerListener.onPlayerCreate(); Log.d(TAG, "Player created."); } @Override public void onPlayerRelease() { sMockSurfaceControllerListener.onPlayerRelease(); Log.d(TAG, "Player released."); } @Override public void onSurfaceCreated(int surfaceId, @NonNull Surface surface, @NonNull String mediaId) { sMockSurfaceControllerListener.onSurfaceCreated(surfaceId, surface, mediaId); Log.d(TAG, "Surface prepared: " + surfaceId + ". Surface: " + surface + ". MediaId: " + mediaId); } @Override public void onSurfaceChanged(int surfaceId, int format, int width, int height) { sMockSurfaceControllerListener.onSurfaceChanged(surfaceId, format, width, height); Log.d(TAG, "Surface changed: " + surfaceId + ". Format: " + format + ". Width: " + width + ". Height: " + height); } @Override public void onSurfaceDestroyed(int surfaceId) { sMockSurfaceControllerListener.onSurfaceDestroyed(surfaceId); Log.d(TAG, "onSurfaceDestroyed: " + surfaceId); } @Override public void onMediaPlay(int surfaceId) { sMockSurfaceControllerListener.onMediaPlay(surfaceId); Log.d(TAG, "onMediaPlay: " + surfaceId); } @Override public void onMediaPause(int surfaceId) { sMockSurfaceControllerListener.onMediaPause(surfaceId); Log.d(TAG, "onMediaPause: " + surfaceId); } @Override public void onMediaSeekTo(int surfaceId, long timestampMillis) { sMockSurfaceControllerListener.onMediaSeekTo(surfaceId, timestampMillis); Log.d(TAG, "Media seeked: " + surfaceId + ". Timestamp: " + timestampMillis); } @Override public void onConfigChange(@NonNull Bundle config) { sMockSurfaceControllerListener.onConfigChange(config); Log.d(TAG, "onConfigChange config: " + config); } @Override public void onDestroy() { sMockSurfaceControllerListener.onDestroy(); Log.d(TAG, "Surface controller destroyed."); } public void sendPlaybackEvent(int surfaceId, int state) { mCallback.setPlaybackState(surfaceId, state, null); } } }