Screenshots: use ImageExporter
Use a single tested module for image export steps which is
now shared between the standard flow and the long screenshot
feature.
Test: ImageExporterTest android.assist.cts.ScreenshotTest
ScreenshotNotificationSmartActionsTest
Bug: 175744393
Fix: 175744393
Change-Id: Id08716736edb4ac1d00c13224e7763e8ca53c979
This commit is contained in:
@@ -306,10 +306,6 @@ class ImageExporter {
|
||||
exif.setAttribute(ExifInterface.TAG_DATETIME_ORIGINAL, dateTime);
|
||||
exif.setAttribute(ExifInterface.TAG_SUBSEC_TIME_ORIGINAL, subSec);
|
||||
exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL, timeZone);
|
||||
|
||||
exif.setAttribute(ExifInterface.TAG_DATETIME_DIGITIZED, dateTime);
|
||||
exif.setAttribute(ExifInterface.TAG_SUBSEC_TIME_DIGITIZED, subSec);
|
||||
exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_DIGITIZED, timeZone);
|
||||
}
|
||||
|
||||
static String getMimeType(CompressFormat format) {
|
||||
|
||||
@@ -27,8 +27,6 @@ import android.app.PendingIntent;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipDescription;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
@@ -36,43 +34,26 @@ import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.provider.MediaStore;
|
||||
import android.provider.MediaStore.MediaColumns;
|
||||
import android.text.TextUtils;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SystemUIFactory;
|
||||
import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ShareTransition;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -99,14 +80,17 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
|
||||
private final boolean mSmartActionsEnabled;
|
||||
private final Random mRandom = new Random();
|
||||
private final Supplier<ShareTransition> mSharedElementTransition;
|
||||
private final ImageExporter mImageExporter;
|
||||
|
||||
SaveImageInBackgroundTask(Context context, ScreenshotSmartActions screenshotSmartActions,
|
||||
SaveImageInBackgroundTask(Context context, ImageExporter exporter,
|
||||
ScreenshotSmartActions screenshotSmartActions,
|
||||
ScreenshotController.SaveImageInBackgroundData data,
|
||||
Supplier<ShareTransition> sharedElementTransition) {
|
||||
mContext = context;
|
||||
mScreenshotSmartActions = screenshotSmartActions;
|
||||
mImageData = new ScreenshotController.SavedImageData();
|
||||
mSharedElementTransition = sharedElementTransition;
|
||||
mImageExporter = exporter;
|
||||
|
||||
// Prepare all the output metadata
|
||||
mParams = data;
|
||||
@@ -139,90 +123,17 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
|
||||
}
|
||||
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
|
||||
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
Bitmap image = mParams.image;
|
||||
|
||||
try {
|
||||
// Save the screenshot to the MediaStore
|
||||
final ContentValues values = new ContentValues();
|
||||
values.put(MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES
|
||||
+ File.separator + Environment.DIRECTORY_SCREENSHOTS);
|
||||
values.put(MediaColumns.DISPLAY_NAME, mImageFileName);
|
||||
values.put(MediaColumns.MIME_TYPE, "image/png");
|
||||
values.put(MediaColumns.DATE_ADDED, mImageTime / 1000);
|
||||
values.put(MediaColumns.DATE_MODIFIED, mImageTime / 1000);
|
||||
values.put(MediaColumns.DATE_EXPIRES, (mImageTime + DateUtils.DAY_IN_MILLIS) / 1000);
|
||||
values.put(MediaColumns.IS_PENDING, 1);
|
||||
|
||||
final Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
|
||||
// Call synchronously here since already on a background thread.
|
||||
Uri uri = mImageExporter.export(Runnable::run, image).get();
|
||||
|
||||
CompletableFuture<List<Notification.Action>> smartActionsFuture =
|
||||
mScreenshotSmartActions.getSmartActionsFuture(
|
||||
mScreenshotId, uri, image, mSmartActionsProvider,
|
||||
mSmartActionsEnabled, getUserHandle(mContext));
|
||||
|
||||
try {
|
||||
// First, write the actual data for our screenshot
|
||||
try (OutputStream out = resolver.openOutputStream(uri)) {
|
||||
if (DEBUG_STORAGE) {
|
||||
Log.d(TAG, "Compressing PNG:"
|
||||
+ " w=" + image.getWidth() + " h=" + image.getHeight());
|
||||
}
|
||||
if (!image.compress(Bitmap.CompressFormat.PNG, 100, out)) {
|
||||
if (DEBUG_STORAGE) {
|
||||
Log.d(TAG, "Bitmap.compress returned false");
|
||||
}
|
||||
throw new IOException("Failed to compress");
|
||||
}
|
||||
if (DEBUG_STORAGE) {
|
||||
Log.d(TAG, "Done compressing PNG");
|
||||
}
|
||||
}
|
||||
|
||||
// Next, write metadata to help index the screenshot
|
||||
try (ParcelFileDescriptor pfd = resolver.openFile(uri, "rw", null)) {
|
||||
final ExifInterface exif = new ExifInterface(pfd.getFileDescriptor());
|
||||
|
||||
exif.setAttribute(ExifInterface.TAG_SOFTWARE,
|
||||
"Android " + Build.DISPLAY);
|
||||
|
||||
exif.setAttribute(ExifInterface.TAG_IMAGE_WIDTH,
|
||||
Integer.toString(image.getWidth()));
|
||||
exif.setAttribute(ExifInterface.TAG_IMAGE_LENGTH,
|
||||
Integer.toString(image.getHeight()));
|
||||
|
||||
final ZonedDateTime time = ZonedDateTime.ofInstant(
|
||||
Instant.ofEpochMilli(mImageTime), ZoneId.systemDefault());
|
||||
exif.setAttribute(ExifInterface.TAG_DATETIME_ORIGINAL,
|
||||
DateTimeFormatter.ofPattern("yyyy:MM:dd HH:mm:ss").format(time));
|
||||
exif.setAttribute(ExifInterface.TAG_SUBSEC_TIME_ORIGINAL,
|
||||
DateTimeFormatter.ofPattern("SSS").format(time));
|
||||
|
||||
if (Objects.equals(time.getOffset(), ZoneOffset.UTC)) {
|
||||
exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL, "+00:00");
|
||||
} else {
|
||||
exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL,
|
||||
DateTimeFormatter.ofPattern("XXX").format(time));
|
||||
}
|
||||
if (DEBUG_STORAGE) {
|
||||
Log.d(TAG, "Writing EXIF metadata");
|
||||
}
|
||||
exif.saveAttributes();
|
||||
}
|
||||
|
||||
// Everything went well above, publish it!
|
||||
values.clear();
|
||||
values.put(MediaColumns.IS_PENDING, 0);
|
||||
values.putNull(MediaColumns.DATE_EXPIRES);
|
||||
resolver.update(uri, values, null, null);
|
||||
if (DEBUG_STORAGE) {
|
||||
Log.d(TAG, "Completed writing to ContentManager");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
resolver.delete(uri, null);
|
||||
throw e;
|
||||
}
|
||||
|
||||
List<Notification.Action> smartActions = new ArrayList<>();
|
||||
if (mSmartActionsEnabled) {
|
||||
int timeoutMs = DeviceConfig.getInt(
|
||||
|
||||
@@ -78,10 +78,13 @@ import com.android.internal.logging.UiEventLogger;
|
||||
import com.android.internal.policy.PhoneWindow;
|
||||
import com.android.settingslib.applications.InterestingConfigChanges;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.dagger.qualifiers.Background;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ShareTransition;
|
||||
import com.android.systemui.util.DeviceConfigProxy;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -166,6 +169,9 @@ public class ScreenshotController {
|
||||
private final ScreenshotNotificationsController mNotificationsController;
|
||||
private final ScreenshotSmartActions mScreenshotSmartActions;
|
||||
private final UiEventLogger mUiEventLogger;
|
||||
private final ImageExporter mImageExporter;
|
||||
private final Executor mMainExecutor;
|
||||
private final Executor mBgExecutor;
|
||||
|
||||
private final WindowManager mWindowManager;
|
||||
private final WindowManager.LayoutParams mWindowLayoutParams;
|
||||
@@ -219,11 +225,17 @@ public class ScreenshotController {
|
||||
ScreenshotNotificationsController screenshotNotificationsController,
|
||||
ScrollCaptureClient scrollCaptureClient,
|
||||
UiEventLogger uiEventLogger,
|
||||
DeviceConfigProxy configProxy) {
|
||||
DeviceConfigProxy configProxy,
|
||||
ImageExporter imageExporter,
|
||||
@Main Executor mainExecutor,
|
||||
@Background Executor bgExecutor) {
|
||||
mScreenshotSmartActions = screenshotSmartActions;
|
||||
mNotificationsController = screenshotNotificationsController;
|
||||
mScrollCaptureClient = scrollCaptureClient;
|
||||
mUiEventLogger = uiEventLogger;
|
||||
mImageExporter = imageExporter;
|
||||
mMainExecutor = mainExecutor;
|
||||
mBgExecutor = bgExecutor;
|
||||
|
||||
final DisplayManager dm = requireNonNull(context.getSystemService(DisplayManager.class));
|
||||
final Display display = dm.getDisplay(DEFAULT_DISPLAY);
|
||||
@@ -502,9 +514,10 @@ public class ScreenshotController {
|
||||
}
|
||||
}
|
||||
|
||||
private void runScrollCapture(ScrollCaptureClient.Connection connection,
|
||||
Runnable after) {
|
||||
new ScrollCaptureController(mContext, connection).run(after);
|
||||
private void runScrollCapture(ScrollCaptureClient.Connection connection, Runnable andThen) {
|
||||
ScrollCaptureController controller = new ScrollCaptureController(mContext, connection,
|
||||
mMainExecutor, mBgExecutor, mImageExporter);
|
||||
controller.run(andThen);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -604,8 +617,8 @@ public class ScreenshotController {
|
||||
mSaveInBgTask.setActionsReadyListener(this::logSuccessOnActionsReady);
|
||||
}
|
||||
|
||||
mSaveInBgTask = new SaveImageInBackgroundTask(mContext, mScreenshotSmartActions, data,
|
||||
getShareTransitionSupplier());
|
||||
mSaveInBgTask = new SaveImageInBackgroundTask(mContext, mImageExporter,
|
||||
mScreenshotSmartActions, data, getShareTransitionSupplier());
|
||||
mSaveInBgTask.execute();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,6 @@ package com.android.systemui.screenshot;
|
||||
|
||||
import static android.graphics.ColorSpace.Named.SRGB;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
@@ -27,33 +25,19 @@ import android.graphics.Canvas;
|
||||
import android.graphics.ColorSpace;
|
||||
import android.graphics.Picture;
|
||||
import android.graphics.Rect;
|
||||
import android.media.ExifInterface;
|
||||
import android.media.Image;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.MediaStore;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.android.systemui.screenshot.ScrollCaptureClient.Connection;
|
||||
import com.android.systemui.screenshot.ScrollCaptureClient.Session;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.sql.Date;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
@@ -67,11 +51,19 @@ public class ScrollCaptureController {
|
||||
|
||||
private final Connection mConnection;
|
||||
private final Context mContext;
|
||||
|
||||
private final Executor mUiExecutor;
|
||||
private final Executor mBgExecutor;
|
||||
private final ImageExporter mImageExporter;
|
||||
private Picture mPicture;
|
||||
|
||||
public ScrollCaptureController(Context context, Connection connection) {
|
||||
public ScrollCaptureController(Context context, Connection connection, Executor uiExecutor,
|
||||
Executor bgExecutor, ImageExporter exporter) {
|
||||
mContext = context;
|
||||
mConnection = connection;
|
||||
mUiExecutor = uiExecutor;
|
||||
mBgExecutor = bgExecutor;
|
||||
mImageExporter = exporter;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,7 +75,7 @@ public class ScrollCaptureController {
|
||||
mConnection.start(MAX_PAGES, (session) -> startCapture(session, after));
|
||||
}
|
||||
|
||||
private void startCapture(Session session, final Runnable after) {
|
||||
private void startCapture(Session session, final Runnable onDismiss) {
|
||||
Rect requestRect = new Rect(0, 0,
|
||||
session.getMaxTileWidth(), session.getMaxTileHeight());
|
||||
Consumer<ScrollCaptureClient.CaptureResult> consumer =
|
||||
@@ -101,20 +93,11 @@ public class ScrollCaptureController {
|
||||
}
|
||||
if (emptyFrame || mFrameCount >= MAX_PAGES
|
||||
|| requestRect.bottom > MAX_HEIGHT) {
|
||||
Uri uri = null;
|
||||
if (mPicture != null) {
|
||||
// This is probably on a binder thread right now ¯\_(ツ)_/¯
|
||||
uri = writeImage(Bitmap.createBitmap(mPicture));
|
||||
// Release those buffers!
|
||||
mPicture.close();
|
||||
}
|
||||
if (uri != null) {
|
||||
launchViewer(uri);
|
||||
exportToFile(mPicture, session, onDismiss);
|
||||
} else {
|
||||
Toast.makeText(mContext, "Failed to create tall screenshot",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
session.end(onDismiss);
|
||||
}
|
||||
session.end(after); // end session, close connection, after.run()
|
||||
return;
|
||||
}
|
||||
requestRect.offset(0, session.getMaxTileHeight());
|
||||
@@ -126,6 +109,22 @@ public class ScrollCaptureController {
|
||||
session.requestTile(requestRect, consumer);
|
||||
};
|
||||
|
||||
void exportToFile(Picture picture, Session session, Runnable afterEnd) {
|
||||
mImageExporter.setFormat(Bitmap.CompressFormat.PNG);
|
||||
mImageExporter.setQuality(6);
|
||||
ListenableFuture<Uri> future =
|
||||
mImageExporter.export(mBgExecutor, Bitmap.createBitmap(picture));
|
||||
future.addListener(() -> {
|
||||
picture.close(); // release resources
|
||||
try {
|
||||
launchViewer(future.get());
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
Toast.makeText(mContext, "Failed to write image", Toast.LENGTH_SHORT).show();
|
||||
Log.e(TAG, "Error storing screenshot to media store", e.getCause());
|
||||
}
|
||||
session.end(afterEnd); // end session, close connection, afterEnd.run()
|
||||
}, mUiExecutor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine the top {@link Picture} with an {@link Image} by appending the image directly
|
||||
@@ -162,79 +161,6 @@ public class ScrollCaptureController {
|
||||
return combined;
|
||||
}
|
||||
|
||||
Uri writeImage(Bitmap image) {
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
long mImageTime = System.currentTimeMillis();
|
||||
String imageDate = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date(mImageTime));
|
||||
String mImageFileName = String.format("tall_Screenshot_%s.png", imageDate);
|
||||
String mScreenshotId = String.format("Screenshot_%s", UUID.randomUUID());
|
||||
try {
|
||||
// Save the screenshot to the MediaStore
|
||||
final ContentValues values = new ContentValues();
|
||||
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES
|
||||
+ File.separator + Environment.DIRECTORY_SCREENSHOTS);
|
||||
values.put(MediaStore.MediaColumns.DISPLAY_NAME, mImageFileName);
|
||||
values.put(MediaStore.MediaColumns.MIME_TYPE, "image/png");
|
||||
values.put(MediaStore.MediaColumns.DATE_ADDED, mImageTime / 1000);
|
||||
values.put(MediaStore.MediaColumns.DATE_MODIFIED, mImageTime / 1000);
|
||||
values.put(
|
||||
MediaStore.MediaColumns.DATE_EXPIRES,
|
||||
(mImageTime + DateUtils.DAY_IN_MILLIS) / 1000);
|
||||
values.put(MediaStore.MediaColumns.IS_PENDING, 1);
|
||||
|
||||
final Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||
values);
|
||||
try {
|
||||
try (OutputStream out = resolver.openOutputStream(uri)) {
|
||||
if (!image.compress(Bitmap.CompressFormat.PNG, 100, out)) {
|
||||
throw new IOException("Failed to compress");
|
||||
}
|
||||
}
|
||||
|
||||
// Next, write metadata to help index the screenshot
|
||||
try (ParcelFileDescriptor pfd = resolver.openFile(uri, "rw", null)) {
|
||||
final ExifInterface exif = new ExifInterface(pfd.getFileDescriptor());
|
||||
|
||||
exif.setAttribute(ExifInterface.TAG_SOFTWARE,
|
||||
"Android " + Build.DISPLAY);
|
||||
|
||||
exif.setAttribute(ExifInterface.TAG_IMAGE_WIDTH,
|
||||
Integer.toString(image.getWidth()));
|
||||
exif.setAttribute(ExifInterface.TAG_IMAGE_LENGTH,
|
||||
Integer.toString(image.getHeight()));
|
||||
|
||||
final ZonedDateTime time = ZonedDateTime.ofInstant(
|
||||
Instant.ofEpochMilli(mImageTime), ZoneId.systemDefault());
|
||||
exif.setAttribute(ExifInterface.TAG_DATETIME_ORIGINAL,
|
||||
DateTimeFormatter.ofPattern("yyyy:MM:dd HH:mm:ss").format(time));
|
||||
exif.setAttribute(ExifInterface.TAG_SUBSEC_TIME_ORIGINAL,
|
||||
DateTimeFormatter.ofPattern("SSS").format(time));
|
||||
|
||||
if (Objects.equals(time.getOffset(), ZoneOffset.UTC)) {
|
||||
exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL, "+00:00");
|
||||
} else {
|
||||
exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL,
|
||||
DateTimeFormatter.ofPattern("XXX").format(time));
|
||||
}
|
||||
exif.saveAttributes();
|
||||
}
|
||||
|
||||
// Everything went well above, publish it!
|
||||
values.clear();
|
||||
values.put(MediaStore.MediaColumns.IS_PENDING, 0);
|
||||
values.putNull(MediaStore.MediaColumns.DATE_EXPIRES);
|
||||
resolver.update(uri, values, null, null);
|
||||
return uri;
|
||||
} catch (Exception e) {
|
||||
resolver.delete(uri, null);
|
||||
throw e;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "unable to save screenshot", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void launchViewer(Uri uri) {
|
||||
Intent editIntent = new Intent(Intent.ACTION_VIEW);
|
||||
editIntent.setType("image/png");
|
||||
|
||||
@@ -85,8 +85,6 @@ public class ImageExporterTest extends SysuiTestCase {
|
||||
|
||||
assertEquals("Exif " + ExifInterface.TAG_OFFSET_TIME_ORIGINAL, "+00:00",
|
||||
exifInterface.getAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL));
|
||||
assertEquals("Exif " + ExifInterface.TAG_OFFSET_TIME_ORIGINAL, "+00:00",
|
||||
exifInterface.getAttribute(ExifInterface.TAG_OFFSET_TIME_DIGITIZED));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -127,13 +125,6 @@ public class ImageExporterTest extends SysuiTestCase {
|
||||
exifInterface.getAttribute(ExifInterface.TAG_SUBSEC_TIME_ORIGINAL));
|
||||
assertEquals("Exif " + ExifInterface.TAG_OFFSET_TIME_ORIGINAL, "-05:00",
|
||||
exifInterface.getAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL));
|
||||
|
||||
assertEquals("Exif " + ExifInterface.TAG_DATETIME_DIGITIZED, "2020:12:15 13:15:00",
|
||||
exifInterface.getAttribute(ExifInterface.TAG_DATETIME_DIGITIZED));
|
||||
assertEquals("Exif " + ExifInterface.TAG_SUBSEC_TIME_DIGITIZED, "000",
|
||||
exifInterface.getAttribute(ExifInterface.TAG_SUBSEC_TIME_DIGITIZED));
|
||||
assertEquals("Exif " + ExifInterface.TAG_OFFSET_TIME_DIGITIZED, "-05:00",
|
||||
exifInterface.getAttribute(ExifInterface.TAG_OFFSET_TIME_DIGITIZED));
|
||||
}
|
||||
} finally {
|
||||
if (decoded != null) {
|
||||
|
||||
@@ -176,7 +176,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase {
|
||||
data.finisher = null;
|
||||
data.mActionsReadyListener = null;
|
||||
SaveImageInBackgroundTask task =
|
||||
new SaveImageInBackgroundTask(mContext, mScreenshotSmartActions, data,
|
||||
new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data,
|
||||
ShareTransition::new);
|
||||
|
||||
Notification.Action shareAction = task.createShareAction(mContext, mContext.getResources(),
|
||||
@@ -204,7 +204,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase {
|
||||
data.finisher = null;
|
||||
data.mActionsReadyListener = null;
|
||||
SaveImageInBackgroundTask task =
|
||||
new SaveImageInBackgroundTask(mContext, mScreenshotSmartActions, data,
|
||||
new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data,
|
||||
ShareTransition::new);
|
||||
|
||||
Notification.Action editAction = task.createEditAction(mContext, mContext.getResources(),
|
||||
@@ -232,7 +232,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase {
|
||||
data.finisher = null;
|
||||
data.mActionsReadyListener = null;
|
||||
SaveImageInBackgroundTask task =
|
||||
new SaveImageInBackgroundTask(mContext, mScreenshotSmartActions, data,
|
||||
new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data,
|
||||
ShareTransition::new);
|
||||
|
||||
Notification.Action deleteAction = task.createDeleteAction(mContext,
|
||||
|
||||
Reference in New Issue
Block a user