Merge "Hide local Picker API and disable it based on flag" into sc-mainline-prod
diff --git a/apex/framework/Android.bp b/apex/framework/Android.bp
index 716f818..ab3bc1c 100644
--- a/apex/framework/Android.bp
+++ b/apex/framework/Android.bp
@@ -44,6 +44,7 @@
     hostdex: true, // for hiddenapi check
     impl_library_visibility: [
         "//packages/providers/MediaProvider:__subpackages__",
+        "//cts/tests/PhotoPicker",
     ],
     apex_available: [
         "com.android.mediaprovider",
diff --git a/apex/framework/api/current.txt b/apex/framework/api/current.txt
index 9d1fd44..061469b 100644
--- a/apex/framework/api/current.txt
+++ b/apex/framework/api/current.txt
@@ -74,7 +74,6 @@
     method public static android.net.Uri getMediaScannerUri();
     method @Nullable public static android.net.Uri getMediaUri(@NonNull android.content.Context, @NonNull android.net.Uri);
     method @NonNull public static android.os.ParcelFileDescriptor getOriginalMediaFormatFileDescriptor(@NonNull android.content.Context, @NonNull android.os.ParcelFileDescriptor) throws java.io.IOException;
-    method public static int getPickImagesMaxLimit();
     method @NonNull public static java.util.Set<java.lang.String> getRecentExternalVolumeNames(@NonNull android.content.Context);
     method @Nullable public static android.net.Uri getRedactedUri(@NonNull android.content.ContentResolver, @NonNull android.net.Uri);
     method @NonNull public static java.util.List<android.net.Uri> getRedactedUri(@NonNull android.content.ContentResolver, @NonNull java.util.List<android.net.Uri>);
@@ -87,7 +86,6 @@
     method @NonNull public static android.net.Uri setRequireOriginal(@NonNull android.net.Uri);
     field public static final String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
     field public static final String ACTION_IMAGE_CAPTURE_SECURE = "android.media.action.IMAGE_CAPTURE_SECURE";
-    field public static final String ACTION_PICK_IMAGES = "android.provider.action.PICK_IMAGES";
     field public static final String ACTION_REVIEW = "android.provider.action.REVIEW";
     field public static final String ACTION_REVIEW_SECURE = "android.provider.action.REVIEW_SECURE";
     field public static final String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE";
@@ -108,7 +106,6 @@
     field public static final String EXTRA_MEDIA_RADIO_CHANNEL = "android.intent.extra.radio_channel";
     field public static final String EXTRA_MEDIA_TITLE = "android.intent.extra.title";
     field public static final String EXTRA_OUTPUT = "output";
-    field public static final String EXTRA_PICK_IMAGES_MAX = "android.provider.extra.PICK_IMAGES_MAX";
     field public static final String EXTRA_SCREEN_ORIENTATION = "android.intent.extra.screenOrientation";
     field public static final String EXTRA_SHOW_ACTION_ICONS = "android.intent.extra.showActionIcons";
     field public static final String EXTRA_SIZE_LIMIT = "android.intent.extra.sizeLimit";
diff --git a/apex/framework/java/android/provider/MediaStore.java b/apex/framework/java/android/provider/MediaStore.java
index 00589e8..efb86a3 100644
--- a/apex/framework/java/android/provider/MediaStore.java
+++ b/apex/framework/java/android/provider/MediaStore.java
@@ -691,6 +691,8 @@
      * {@link Activity#RESULT_CANCELED} is returned.
      * <p>
      * Output: MediaStore content URI(s) of the item(s) that was picked.
+     *
+     * @hide
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_PICK_IMAGES = "android.provider.action.PICK_IMAGES";
@@ -705,6 +707,8 @@
      * than 1 and less than or equal to
      * {@link MediaStore#getPickImagesMaxLimit}, otherwise
      * {@link Activity#RESULT_CANCELED} is returned.
+     *
+     * @hide
      */
     public final static String EXTRA_PICK_IMAGES_MAX = "android.provider.extra.PICK_IMAGES_MAX";
 
@@ -712,6 +716,8 @@
      * The maximum limit for the number of items that can be selected using
      * {@link MediaStore#ACTION_PICK_IMAGES} when launched in multiple selection mode.
      * This can be used as a constant value for {@link MediaStore#EXTRA_PICK_IMAGES_MAX}.
+     *
+     * @hide
      */
     public static int getPickImagesMaxLimit() {
         return PICK_IMAGES_MAX_LIMIT;
diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java
index 90bfdbc..35d5077 100644
--- a/src/com/android/providers/media/MediaProvider.java
+++ b/src/com/android/providers/media/MediaProvider.java
@@ -88,6 +88,8 @@
 import static com.android.providers.media.util.FileUtils.isExternalMediaDirectory;
 import static com.android.providers.media.util.FileUtils.isObbOrChildPath;
 import static com.android.providers.media.util.FileUtils.sanitizePath;
+import static com.android.providers.media.util.Logging.LOGV;
+import static com.android.providers.media.util.Logging.TAG;
 import static com.android.providers.media.util.SyntheticPathUtils.REDACTED_URI_ID_PREFIX;
 import static com.android.providers.media.util.SyntheticPathUtils.REDACTED_URI_ID_SIZE;
 import static com.android.providers.media.util.SyntheticPathUtils.createSparseFile;
@@ -96,8 +98,6 @@
 import static com.android.providers.media.util.SyntheticPathUtils.isPickerPath;
 import static com.android.providers.media.util.SyntheticPathUtils.isRedactedPath;
 import static com.android.providers.media.util.SyntheticPathUtils.isSyntheticPath;
-import static com.android.providers.media.util.Logging.LOGV;
-import static com.android.providers.media.util.Logging.TAG;
 
 import android.app.AppOpsManager;
 import android.app.AppOpsManager.OnOpActiveChangedListener;
diff --git a/src/com/android/providers/media/photopicker/PhotoPickerActivity.java b/src/com/android/providers/media/photopicker/PhotoPickerActivity.java
index a541480..c092d30 100644
--- a/src/com/android/providers/media/photopicker/PhotoPickerActivity.java
+++ b/src/com/android/providers/media/photopicker/PhotoPickerActivity.java
@@ -28,7 +28,10 @@
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.Binder;
 import android.os.Bundle;
+import android.os.SystemProperties;
+import android.provider.DeviceConfig;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -44,6 +47,7 @@
 import androidx.appcompat.widget.Toolbar;
 import androidx.lifecycle.ViewModelProvider;
 
+import com.android.modules.utils.build.SdkLevel;
 import com.android.providers.media.R;
 import com.android.providers.media.photopicker.data.Selection;
 import com.android.providers.media.photopicker.data.model.Category;
@@ -99,6 +103,11 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+
+        if (!isPhotoPickerEnabled()) {
+            setCancelledResultAndFinishSelf();
+        }
+
         setContentView(R.layout.activity_photo_picker);
 
         mToolbar = findViewById(R.id.toolbar);
@@ -135,6 +144,44 @@
     }
 
     /**
+     * TODO(b/205291616) Remove this before launch. This is a temporary method to hide the API
+     * until we are ready to launch it.
+     */
+    @VisibleForTesting
+    public boolean isPhotoPickerEnabled() {
+        // Always enabled on T+
+        if (SdkLevel.isAtLeastT()) {
+            return true;
+        }
+
+        // If the system property is enabled, then picker is enabled
+        boolean isSysPropertyEnabled =
+                SystemProperties.getBoolean(
+                        "persist.sys.storage_picker_enabled" /* key */,
+                        false /* def */);
+        if (isSysPropertyEnabled) {
+            return true;
+        }
+
+        // If build is < S, then picker is disabled since we cannot check device config
+        if (!SdkLevel.isAtLeastS()) {
+            // We cannot read device config on R
+            return false;
+        }
+
+        // If the device config is enabled, then picker is enabled
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return DeviceConfig.getBoolean(
+                    DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+                    "picker_intent_enabled",
+                    false /* defaultValue */ );
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    /**
      * Warning: This method is needed for tests, we are not customizing anything here.
      * Allowing ourselves to control ViewModel creation helps us mock the ViewModel for test.
      */
diff --git a/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerTestActivity.java b/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerTestActivity.java
index 55dcd99..8577da7 100644
--- a/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerTestActivity.java
+++ b/tests/src/com/android/providers/media/photopicker/espresso/PhotoPickerTestActivity.java
@@ -29,4 +29,9 @@
         pickerViewModel.setUserIdManager(PhotoPickerBaseTest.getMockUserIdManager());
         return pickerViewModel;
     }
+
+    @Override
+    public boolean isPhotoPickerEnabled() {
+        return true;
+    }
 }
\ No newline at end of file