Merge "Only honor passed-in userid value if work profile flag enabled" into tm-qpr-dev
This commit is contained in:
@@ -38,6 +38,8 @@ import androidx.concurrent.futures.CallbackToFutureAdapter;
|
|||||||
import androidx.exifinterface.media.ExifInterface;
|
import androidx.exifinterface.media.ExifInterface;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
import com.android.systemui.flags.FeatureFlags;
|
||||||
|
import com.android.systemui.flags.Flags;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
@@ -85,10 +87,12 @@ class ImageExporter {
|
|||||||
private final ContentResolver mResolver;
|
private final ContentResolver mResolver;
|
||||||
private CompressFormat mCompressFormat = CompressFormat.PNG;
|
private CompressFormat mCompressFormat = CompressFormat.PNG;
|
||||||
private int mQuality = 100;
|
private int mQuality = 100;
|
||||||
|
private final FeatureFlags mFlags;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ImageExporter(ContentResolver resolver) {
|
ImageExporter(ContentResolver resolver, FeatureFlags flags) {
|
||||||
mResolver = resolver;
|
mResolver = resolver;
|
||||||
|
mFlags = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -161,7 +165,7 @@ class ImageExporter {
|
|||||||
ZonedDateTime captureTime, UserHandle owner) {
|
ZonedDateTime captureTime, UserHandle owner) {
|
||||||
|
|
||||||
final Task task = new Task(mResolver, requestId, bitmap, captureTime, mCompressFormat,
|
final Task task = new Task(mResolver, requestId, bitmap, captureTime, mCompressFormat,
|
||||||
mQuality, /* publish */ true, owner);
|
mQuality, /* publish */ true, owner, mFlags);
|
||||||
|
|
||||||
return CallbackToFutureAdapter.getFuture(
|
return CallbackToFutureAdapter.getFuture(
|
||||||
(completer) -> {
|
(completer) -> {
|
||||||
@@ -209,9 +213,11 @@ class ImageExporter {
|
|||||||
private final UserHandle mOwner;
|
private final UserHandle mOwner;
|
||||||
private final String mFileName;
|
private final String mFileName;
|
||||||
private final boolean mPublish;
|
private final boolean mPublish;
|
||||||
|
private final FeatureFlags mFlags;
|
||||||
|
|
||||||
Task(ContentResolver resolver, UUID requestId, Bitmap bitmap, ZonedDateTime captureTime,
|
Task(ContentResolver resolver, UUID requestId, Bitmap bitmap, ZonedDateTime captureTime,
|
||||||
CompressFormat format, int quality, boolean publish, UserHandle owner) {
|
CompressFormat format, int quality, boolean publish, UserHandle owner,
|
||||||
|
FeatureFlags flags) {
|
||||||
mResolver = resolver;
|
mResolver = resolver;
|
||||||
mRequestId = requestId;
|
mRequestId = requestId;
|
||||||
mBitmap = bitmap;
|
mBitmap = bitmap;
|
||||||
@@ -221,6 +227,7 @@ class ImageExporter {
|
|||||||
mOwner = owner;
|
mOwner = owner;
|
||||||
mFileName = createFilename(mCaptureTime, mFormat);
|
mFileName = createFilename(mCaptureTime, mFormat);
|
||||||
mPublish = publish;
|
mPublish = publish;
|
||||||
|
mFlags = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result execute() throws ImageExportException, InterruptedException {
|
public Result execute() throws ImageExportException, InterruptedException {
|
||||||
@@ -234,7 +241,7 @@ class ImageExporter {
|
|||||||
start = Instant.now();
|
start = Instant.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
uri = createEntry(mResolver, mFormat, mCaptureTime, mFileName, mOwner);
|
uri = createEntry(mResolver, mFormat, mCaptureTime, mFileName, mOwner, mFlags);
|
||||||
throwIfInterrupted();
|
throwIfInterrupted();
|
||||||
|
|
||||||
writeImage(mResolver, mBitmap, mFormat, mQuality, uri);
|
writeImage(mResolver, mBitmap, mFormat, mQuality, uri);
|
||||||
@@ -278,13 +285,15 @@ class ImageExporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Uri createEntry(ContentResolver resolver, CompressFormat format,
|
private static Uri createEntry(ContentResolver resolver, CompressFormat format,
|
||||||
ZonedDateTime time, String fileName, UserHandle owner) throws ImageExportException {
|
ZonedDateTime time, String fileName, UserHandle owner, FeatureFlags flags)
|
||||||
|
throws ImageExportException {
|
||||||
Trace.beginSection("ImageExporter_createEntry");
|
Trace.beginSection("ImageExporter_createEntry");
|
||||||
try {
|
try {
|
||||||
final ContentValues values = createMetadata(time, format, fileName);
|
final ContentValues values = createMetadata(time, format, fileName);
|
||||||
|
|
||||||
Uri baseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
Uri baseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
||||||
if (UserHandle.myUserId() != owner.getIdentifier()) {
|
if (flags.isEnabled(Flags.SCREENSHOT_WORK_PROFILE_POLICY)
|
||||||
|
&& UserHandle.myUserId() != owner.getIdentifier()) {
|
||||||
baseUri = ContentProvider.maybeAddUserId(baseUri, owner.getIdentifier());
|
baseUri = ContentProvider.maybeAddUserId(baseUri, owner.getIdentifier());
|
||||||
}
|
}
|
||||||
Uri uri = resolver.insert(baseUri, values);
|
Uri uri = resolver.insert(baseUri, values);
|
||||||
|
|||||||
@@ -1043,8 +1043,13 @@ public class ScreenshotController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isUserSetupComplete(UserHandle owner) {
|
private boolean isUserSetupComplete(UserHandle owner) {
|
||||||
return Settings.Secure.getInt(mContext.createContextAsUser(owner, 0)
|
if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)) {
|
||||||
.getContentResolver(), SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1;
|
return Settings.Secure.getInt(mContext.createContextAsUser(owner, 0)
|
||||||
|
.getContentResolver(), SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1;
|
||||||
|
} else {
|
||||||
|
return Settings.Secure.getInt(mContext.getContentResolver(),
|
||||||
|
SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertTrue;
|
|||||||
|
|
||||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||||
|
|
||||||
|
import android.content.ContentProvider;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
@@ -31,9 +32,11 @@ import android.graphics.BitmapFactory;
|
|||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
|
import android.os.UserHandle;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
|
|
||||||
@@ -41,11 +44,18 @@ import androidx.exifinterface.media.ExifInterface;
|
|||||||
import androidx.test.filters.MediumTest;
|
import androidx.test.filters.MediumTest;
|
||||||
|
|
||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
|
import com.android.systemui.flags.FakeFeatureFlags;
|
||||||
|
import com.android.systemui.flags.Flags;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -60,7 +70,6 @@ import java.util.concurrent.Executor;
|
|||||||
@RunWith(AndroidTestingRunner.class)
|
@RunWith(AndroidTestingRunner.class)
|
||||||
@MediumTest // file I/O
|
@MediumTest // file I/O
|
||||||
public class ImageExporterTest extends SysuiTestCase {
|
public class ImageExporterTest extends SysuiTestCase {
|
||||||
|
|
||||||
/** Executes directly in the caller's thread */
|
/** Executes directly in the caller's thread */
|
||||||
private static final Executor DIRECT_EXECUTOR = Runnable::run;
|
private static final Executor DIRECT_EXECUTOR = Runnable::run;
|
||||||
private static final byte[] EXIF_FILE_TAG = "Exif\u0000\u0000".getBytes(US_ASCII);
|
private static final byte[] EXIF_FILE_TAG = "Exif\u0000\u0000".getBytes(US_ASCII);
|
||||||
@@ -68,6 +77,15 @@ public class ImageExporterTest extends SysuiTestCase {
|
|||||||
private static final ZonedDateTime CAPTURE_TIME =
|
private static final ZonedDateTime CAPTURE_TIME =
|
||||||
ZonedDateTime.of(LocalDateTime.of(2020, 12, 15, 13, 15), ZoneId.of("EST"));
|
ZonedDateTime.of(LocalDateTime.of(2020, 12, 15, 13, 15), ZoneId.of("EST"));
|
||||||
|
|
||||||
|
private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
|
||||||
|
@Mock
|
||||||
|
private ContentResolver mMockContentResolver;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testImageFilename() {
|
public void testImageFilename() {
|
||||||
assertEquals("image file name", "Screenshot_20201215-131500.png",
|
assertEquals("image file name", "Screenshot_20201215-131500.png",
|
||||||
@@ -92,7 +110,8 @@ public class ImageExporterTest extends SysuiTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testImageExport() throws ExecutionException, InterruptedException, IOException {
|
public void testImageExport() throws ExecutionException, InterruptedException, IOException {
|
||||||
ContentResolver contentResolver = mContext.getContentResolver();
|
ContentResolver contentResolver = mContext.getContentResolver();
|
||||||
ImageExporter exporter = new ImageExporter(contentResolver);
|
mFeatureFlags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true);
|
||||||
|
ImageExporter exporter = new ImageExporter(contentResolver, mFeatureFlags);
|
||||||
|
|
||||||
UUID requestId = UUID.fromString("3c11da99-9284-4863-b1d5-6f3684976814");
|
UUID requestId = UUID.fromString("3c11da99-9284-4863-b1d5-6f3684976814");
|
||||||
Bitmap original = createCheckerBitmap(10, 10, 10);
|
Bitmap original = createCheckerBitmap(10, 10, 10);
|
||||||
@@ -168,6 +187,44 @@ public class ImageExporterTest extends SysuiTestCase {
|
|||||||
values.getAsLong(MediaStore.MediaColumns.DATE_EXPIRES));
|
values.getAsLong(MediaStore.MediaColumns.DATE_EXPIRES));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetUser() {
|
||||||
|
mFeatureFlags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true);
|
||||||
|
ImageExporter exporter = new ImageExporter(mMockContentResolver, mFeatureFlags);
|
||||||
|
|
||||||
|
UserHandle imageUserHande = UserHandle.of(10);
|
||||||
|
|
||||||
|
ArgumentCaptor<Uri> uriCaptor = ArgumentCaptor.forClass(Uri.class);
|
||||||
|
// Capture the URI and then return null to bail out of export.
|
||||||
|
Mockito.when(mMockContentResolver.insert(uriCaptor.capture(), Mockito.any())).thenReturn(
|
||||||
|
null);
|
||||||
|
exporter.export(DIRECT_EXECUTOR, UUID.fromString("3c11da99-9284-4863-b1d5-6f3684976814"),
|
||||||
|
null, CAPTURE_TIME, imageUserHande);
|
||||||
|
|
||||||
|
Uri expected = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
||||||
|
expected = ContentProvider.maybeAddUserId(expected, imageUserHande.getIdentifier());
|
||||||
|
|
||||||
|
assertEquals(expected, uriCaptor.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetUser_noWorkProfile() {
|
||||||
|
mFeatureFlags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false);
|
||||||
|
ImageExporter exporter = new ImageExporter(mMockContentResolver, mFeatureFlags);
|
||||||
|
|
||||||
|
UserHandle imageUserHandle = UserHandle.of(10);
|
||||||
|
|
||||||
|
ArgumentCaptor<Uri> uriCaptor = ArgumentCaptor.forClass(Uri.class);
|
||||||
|
// Capture the URI and then return null to bail out of export.
|
||||||
|
Mockito.when(mMockContentResolver.insert(uriCaptor.capture(), Mockito.any())).thenReturn(
|
||||||
|
null);
|
||||||
|
exporter.export(DIRECT_EXECUTOR, UUID.fromString("3c11da99-9284-4863-b1d5-6f3684976814"),
|
||||||
|
null, CAPTURE_TIME, imageUserHandle);
|
||||||
|
|
||||||
|
// The user handle should be ignored here since the flag is off.
|
||||||
|
assertEquals(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, uriCaptor.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("SameParameterValue")
|
@SuppressWarnings("SameParameterValue")
|
||||||
private Bitmap createCheckerBitmap(int tileSize, int w, int h) {
|
private Bitmap createCheckerBitmap(int tileSize, int w, int h) {
|
||||||
Bitmap bitmap = Bitmap.createBitmap(w * tileSize, h * tileSize, Bitmap.Config.ARGB_8888);
|
Bitmap bitmap = Bitmap.createBitmap(w * tileSize, h * tileSize, Bitmap.Config.ARGB_8888);
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ import org.mockito.Mockito.verifyZeroInteractions
|
|||||||
import org.mockito.Mockito.`when` as whenever
|
import org.mockito.Mockito.`when` as whenever
|
||||||
|
|
||||||
private const val USER_ID = 1
|
private const val USER_ID = 1
|
||||||
private const val TASK_ID = 1
|
private const val TASK_ID = 11
|
||||||
|
|
||||||
@RunWith(AndroidTestingRunner::class)
|
@RunWith(AndroidTestingRunner::class)
|
||||||
@SmallTest
|
@SmallTest
|
||||||
|
|||||||
Reference in New Issue
Block a user