| /* |
| * Copyright (C) 2021 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 com.android.providers.media.cloudproviders; |
| |
| import static android.provider.CloudMediaProviderContract.EXTRA_PAGE_TOKEN; |
| |
| import static com.android.providers.media.PickerProviderMediaGenerator.MediaGenerator; |
| |
| import static java.util.concurrent.TimeUnit.MILLISECONDS; |
| |
| 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.provider.CloudMediaProvider; |
| import android.util.Log; |
| |
| import androidx.annotation.VisibleForTesting; |
| |
| import com.android.providers.media.PickerProviderMediaGenerator; |
| import com.android.providers.media.photopicker.data.CloudProviderQueryExtras; |
| |
| import java.io.FileNotFoundException; |
| |
| /** |
| * Implements a cloud {@link CloudMediaProvider} interface over items generated with {@link |
| * MediaGenerator} |
| * |
| * <p>This provider is intentionally very flaky and will throw a {@link RuntimeException} for two |
| * out of every three requests. |
| */ |
| public class FlakyCloudProvider extends CloudMediaProvider { |
| private static final String TAG = "FlakyCloudProvider"; |
| public static final String AUTHORITY = |
| "com.android.providers.media.photopicker.tests.cloud_flaky"; |
| public static final String ACCOUNT_NAME = "test_account@flakyCloudProvider"; |
| private static final int INITIAL_REQUEST_COUNT = 0; |
| private static final int REQUEST_COUNT_FOR_NEXT_ONE_TO_FLAKE = 2; |
| |
| private final MediaGenerator mMediaGenerator = |
| PickerProviderMediaGenerator.getMediaGenerator(AUTHORITY); |
| |
| private int mRequestCount = INITIAL_REQUEST_COUNT; |
| |
| /** Determines if the current request should flake. */ |
| private boolean shouldFlake() { |
| |
| // Always succeed on the first request. |
| if (++mRequestCount < REQUEST_COUNT_FOR_NEXT_ONE_TO_FLAKE) { |
| return false; |
| } |
| |
| if (mRequestCount > REQUEST_COUNT_FOR_NEXT_ONE_TO_FLAKE) { |
| mRequestCount = INITIAL_REQUEST_COUNT; |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public boolean onCreate() { |
| mMediaGenerator.setAccountInfo(ACCOUNT_NAME, /* configIntent= */ null); |
| return true; |
| } |
| |
| @Override |
| public Cursor onQueryMedia(Bundle extras) { |
| final CloudProviderQueryExtras queryExtras = |
| CloudProviderQueryExtras.fromCloudMediaBundle(extras); |
| |
| if (shouldFlake()) { |
| throw new RuntimeException("Simulating a crash in FlakyCloudProvider onQueryMedia"); |
| } |
| |
| String pageToken = extras.getString(EXTRA_PAGE_TOKEN, null); |
| |
| return mMediaGenerator.getMedia( |
| queryExtras.getGeneration(), |
| queryExtras.getAlbumId(), |
| queryExtras.getMimeTypes(), |
| queryExtras.getSizeBytes(), |
| pageToken, |
| queryExtras.getPageSize()); |
| } |
| |
| @Override |
| public Cursor onQueryDeletedMedia(Bundle extras) { |
| final CloudProviderQueryExtras queryExtras = |
| CloudProviderQueryExtras.fromCloudMediaBundle(extras); |
| |
| if (shouldFlake()) { |
| throw new RuntimeException( |
| "Simulating a crash in FlakyCloudProvider onQueryDeletedMedia"); |
| } |
| |
| String pageToken = extras.getString(EXTRA_PAGE_TOKEN, null); |
| |
| return mMediaGenerator.getDeletedMedia(queryExtras.getGeneration(), pageToken); |
| } |
| |
| @Override |
| public Cursor onQueryAlbums(Bundle extras) { |
| final CloudProviderQueryExtras queryExtras = |
| CloudProviderQueryExtras.fromCloudMediaBundle(extras); |
| |
| if (shouldFlake()) { |
| throw new RuntimeException("Simulating a crash in FlakyCloudProvider onQueryAlbums"); |
| } |
| |
| String pageToken = extras.getString(EXTRA_PAGE_TOKEN, null); |
| |
| return mMediaGenerator.getAlbums( |
| queryExtras.getMimeTypes(), |
| queryExtras.getSizeBytes(), /* isLocal */ |
| false, |
| pageToken); |
| } |
| |
| @Override |
| public AssetFileDescriptor onOpenPreview( |
| String mediaId, Point size, Bundle extras, CancellationSignal signal) |
| throws FileNotFoundException { |
| throw new UnsupportedOperationException("onOpenPreview not supported"); |
| } |
| |
| @Override |
| public ParcelFileDescriptor onOpenMedia( |
| String mediaId, Bundle extras, CancellationSignal signal) throws FileNotFoundException { |
| throw new UnsupportedOperationException("onOpenMedia not supported"); |
| } |
| |
| @Override |
| public Bundle onGetMediaCollectionInfo(Bundle extras) { |
| if (shouldFlake()) { |
| try { |
| MILLISECONDS.sleep(/* timeout= */ 200L); |
| } catch (InterruptedException e) { |
| Log.d(TAG, "Error while sleep when should flake on get media collection info.", e); |
| } |
| } |
| |
| return mMediaGenerator.getMediaCollectionInfo(); |
| } |
| |
| @VisibleForTesting |
| public void resetToNotFlakeInTheNextRequest() { |
| mRequestCount = INITIAL_REQUEST_COUNT; |
| } |
| |
| @VisibleForTesting |
| public void setToFlakeInTheNextRequest() { |
| mRequestCount = REQUEST_COUNT_FOR_NEXT_ONE_TO_FLAKE; |
| } |
| } |