summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
author Jeff Sharkey <jsharkey@android.com> 2020-05-11 10:54:22 -0600
committer Jeff Sharkey <jsharkey@android.com> 2020-05-11 10:54:24 -0600
commit02a810c849b571e5549d44e39da799d80aa746fb (patch)
treec0fa7fdc61555a84950ec6751e4095fbfccaab32 /tools
parentcccb2aef315097a1a5c6fc9d2b8ebd1fb2b85bc0 (diff)
Add tool used to verify dialog behaviors.
We wrote this tool several months ago to exercise all the various permutations of MediaStore dialogs, but never merged it into the tree until now. This is typically used by PM, UX, and a11y teams to verify behaviors in various edge cases. Bug: 156257943 Test: manual Change-Id: Ib301298d77028d0854ec4ac4c2e8cb2047156a89
Diffstat (limited to 'tools')
-rw-r--r--tools/dialogs/Android.bp6
-rw-r--r--tools/dialogs/AndroidManifest.xml15
-rw-r--r--tools/dialogs/src/com/android/providers/media/tools/dialogs/DialogsActivity.java163
3 files changed, 184 insertions, 0 deletions
diff --git a/tools/dialogs/Android.bp b/tools/dialogs/Android.bp
new file mode 100644
index 000000000..8d2c00049
--- /dev/null
+++ b/tools/dialogs/Android.bp
@@ -0,0 +1,6 @@
+android_app {
+ name: "MediaProviderDialogsTool",
+ manifest: "AndroidManifest.xml",
+ srcs: ["src/**/*.java"],
+ sdk_version: "system_current",
+}
diff --git a/tools/dialogs/AndroidManifest.xml b/tools/dialogs/AndroidManifest.xml
new file mode 100644
index 000000000..947f1bd1d
--- /dev/null
+++ b/tools/dialogs/AndroidManifest.xml
@@ -0,0 +1,15 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.providers.media.tools.dialogs">
+
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+ <application android:label="DialogsTool">
+ <activity android:name=".DialogsActivity">
+ <intent-filter android:label="DialogsTool">
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tools/dialogs/src/com/android/providers/media/tools/dialogs/DialogsActivity.java b/tools/dialogs/src/com/android/providers/media/tools/dialogs/DialogsActivity.java
new file mode 100644
index 000000000..4ff1731da
--- /dev/null
+++ b/tools/dialogs/src/com/android/providers/media/tools/dialogs/DialogsActivity.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2020 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.tools.dialogs;
+
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.provider.MediaStore;
+import android.provider.MediaStore.Files.FileColumns;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.NumberPicker;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+public class DialogsActivity extends Activity {
+ private LinearLayout mBody;
+ private LinearLayout mSpinners;
+
+ private NumberPicker mAudioCount;
+ private NumberPicker mVideoCount;
+ private NumberPicker mImageCount;
+
+ private final ArrayList<Uri> mAudio = new ArrayList<>();
+ private final ArrayList<Uri> mVideo = new ArrayList<>();
+ private final ArrayList<Uri> mImage = new ArrayList<>();
+
+ private final Supplier<Collection<Uri>> mRequestItems = () -> {
+ final ArrayList<Uri> uris = new ArrayList<>();
+ uris.addAll(mAudio.stream().limit(mAudioCount.getValue()).collect(Collectors.toList()));
+ uris.addAll(mVideo.stream().limit(mVideoCount.getValue()).collect(Collectors.toList()));
+ uris.addAll(mImage.stream().limit(mImageCount.getValue()).collect(Collectors.toList()));
+ return uris;
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (checkSelfPermission(READ_EXTERNAL_STORAGE) != PERMISSION_GRANTED
+ || checkSelfPermission(WRITE_EXTERNAL_STORAGE) != PERMISSION_GRANTED) {
+ requestPermissions(new String[] { READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE }, 42);
+ finish();
+ return;
+ }
+
+ mBody = new LinearLayout(this);
+ mBody.setOrientation(LinearLayout.VERTICAL);
+ setContentView(mBody);
+
+ final TextView header = new TextView(this);
+ header.setText("Select the number of items to include in the request using the spinners "
+ + "below; each spinnner in order selects the number audio, video, "
+ + "and image items, respectively.");
+ mBody.addView(header);
+
+ mSpinners = new LinearLayout(this);
+ mSpinners.setOrientation(LinearLayout.HORIZONTAL);
+ mBody.addView(mSpinners);
+
+ mAudioCount = addSpinner();
+ mVideoCount = addSpinner();
+ mImageCount = addSpinner();
+
+ addAction("Request write", () -> {
+ return MediaStore.createWriteRequest(getContentResolver(), mRequestItems.get());
+ });
+ addAction("Request trash", () -> {
+ return MediaStore.createTrashRequest(getContentResolver(), mRequestItems.get(), true);
+ });
+ addAction("Request untrash", () -> {
+ return MediaStore.createTrashRequest(getContentResolver(), mRequestItems.get(), false);
+ });
+ addAction("Request delete", () -> {
+ return MediaStore.createDeleteRequest(getContentResolver(), mRequestItems.get());
+ });
+
+ new BackgroundTask().execute();
+ }
+
+ private class BackgroundTask extends AsyncTask<Void, Void, Void> {
+ @Override
+ protected Void doInBackground(Void... params) {
+ try (Cursor c = getContentResolver().query(
+ MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY),
+ new String[] { FileColumns._ID, FileColumns.MEDIA_TYPE }, null, null, null)) {
+ while (c.moveToNext()) {
+ final long id = c.getLong(0);
+ final int mediaType = c.getInt(1);
+ switch (mediaType) {
+ case FileColumns.MEDIA_TYPE_AUDIO:
+ mAudio.add(MediaStore.Audio.Media
+ .getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY, id));
+ break;
+ case FileColumns.MEDIA_TYPE_VIDEO:
+ mVideo.add(MediaStore.Video.Media
+ .getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY, id));
+ break;
+ case FileColumns.MEDIA_TYPE_IMAGE:
+ mImage.add(MediaStore.Images.Media
+ .getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY, id));
+ break;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void results) {
+ mAudioCount.setMaxValue(mAudio.size());
+ mVideoCount.setMaxValue(mVideo.size());
+ mImageCount.setMaxValue(mImage.size());
+ }
+ }
+
+ private NumberPicker addSpinner() {
+ final NumberPicker spinner = new NumberPicker(this);
+ spinner.setValue(0);
+ spinner.setMaxValue(0);
+ mSpinners.addView(spinner);
+ return spinner;
+ }
+
+ private Button addAction(String title, Supplier<PendingIntent> supplier) {
+ final Button button = new Button(this);
+ button.setText(title);
+ button.setOnClickListener((v) -> {
+ try {
+ startIntentSenderForResult(supplier.get().getIntentSender(), 42, null, 0, 0, 0);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
+ mBody.addView(button);
+ return button;
+ }
+}