Merge changes from topic "fix-flake" into udc-dev
* changes: Update AppClipsActivityTest to use real ViewModel. Update app clips package style. Update screenshot class visibilities for app clips.
This commit is contained in:
committed by
Android (Google) Code Review
commit
334b55d700
@@ -23,9 +23,9 @@ import com.android.systemui.hdmi.HdmiCecSetMenuLanguageActivity;
|
|||||||
import com.android.systemui.keyguard.WorkLockActivity;
|
import com.android.systemui.keyguard.WorkLockActivity;
|
||||||
import com.android.systemui.people.PeopleSpaceActivity;
|
import com.android.systemui.people.PeopleSpaceActivity;
|
||||||
import com.android.systemui.people.widget.LaunchConversationActivity;
|
import com.android.systemui.people.widget.LaunchConversationActivity;
|
||||||
import com.android.systemui.screenshot.AppClipsActivity;
|
|
||||||
import com.android.systemui.screenshot.AppClipsTrampolineActivity;
|
|
||||||
import com.android.systemui.screenshot.LongScreenshotActivity;
|
import com.android.systemui.screenshot.LongScreenshotActivity;
|
||||||
|
import com.android.systemui.screenshot.appclips.AppClipsActivity;
|
||||||
|
import com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity;
|
||||||
import com.android.systemui.sensorprivacy.SensorUseStartedActivity;
|
import com.android.systemui.sensorprivacy.SensorUseStartedActivity;
|
||||||
import com.android.systemui.sensorprivacy.television.TvSensorPrivacyChangedActivity;
|
import com.android.systemui.sensorprivacy.television.TvSensorPrivacyChangedActivity;
|
||||||
import com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity;
|
import com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ package com.android.systemui.notetask
|
|||||||
|
|
||||||
import com.android.systemui.notetask.quickaffordance.NoteTaskQuickAffordanceConfig
|
import com.android.systemui.notetask.quickaffordance.NoteTaskQuickAffordanceConfig
|
||||||
import com.android.systemui.notetask.shortcut.LaunchNoteTaskActivity
|
import com.android.systemui.notetask.shortcut.LaunchNoteTaskActivity
|
||||||
import com.android.systemui.screenshot.AppClipsTrampolineActivity
|
import com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Supported entry points for [NoteTaskController.showNoteTask].
|
* Supported entry points for [NoteTaskController.showNoteTask].
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ import java.util.concurrent.Executor;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
class ImageExporter {
|
/** A class to help with exporting screenshot to storage. */
|
||||||
|
public class ImageExporter {
|
||||||
private static final String TAG = LogConfig.logTag(ImageExporter.class);
|
private static final String TAG = LogConfig.logTag(ImageExporter.class);
|
||||||
|
|
||||||
static final Duration PENDING_ENTRY_TTL = Duration.ofHours(24);
|
static final Duration PENDING_ENTRY_TTL = Duration.ofHours(24);
|
||||||
@@ -90,7 +91,7 @@ class ImageExporter {
|
|||||||
private final FeatureFlags mFlags;
|
private final FeatureFlags mFlags;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ImageExporter(ContentResolver resolver, FeatureFlags flags) {
|
public ImageExporter(ContentResolver resolver, FeatureFlags flags) {
|
||||||
mResolver = resolver;
|
mResolver = resolver;
|
||||||
mFlags = flags;
|
mFlags = flags;
|
||||||
}
|
}
|
||||||
@@ -148,7 +149,7 @@ class ImageExporter {
|
|||||||
*
|
*
|
||||||
* @return a listenable future result
|
* @return a listenable future result
|
||||||
*/
|
*/
|
||||||
ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap,
|
public ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap,
|
||||||
UserHandle owner) {
|
UserHandle owner) {
|
||||||
return export(executor, requestId, bitmap, ZonedDateTime.now(), owner);
|
return export(executor, requestId, bitmap, ZonedDateTime.now(), owner);
|
||||||
}
|
}
|
||||||
@@ -181,13 +182,14 @@ class ImageExporter {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Result {
|
/** The result returned by the task exporting screenshots to storage. */
|
||||||
Uri uri;
|
public static class Result {
|
||||||
UUID requestId;
|
public Uri uri;
|
||||||
String fileName;
|
public UUID requestId;
|
||||||
long timestamp;
|
public String fileName;
|
||||||
CompressFormat format;
|
public long timestamp;
|
||||||
boolean published;
|
public CompressFormat format;
|
||||||
|
public boolean published;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|||||||
@@ -93,13 +93,7 @@ public enum ScreenshotEvent implements UiEventLogger.UiEventEnum {
|
|||||||
@UiEvent(doc = "User has discarded the result of a long screenshot")
|
@UiEvent(doc = "User has discarded the result of a long screenshot")
|
||||||
SCREENSHOT_LONG_SCREENSHOT_EXIT(911),
|
SCREENSHOT_LONG_SCREENSHOT_EXIT(911),
|
||||||
@UiEvent(doc = "A screenshot has been taken and saved to work profile")
|
@UiEvent(doc = "A screenshot has been taken and saved to work profile")
|
||||||
SCREENSHOT_SAVED_TO_WORK_PROFILE(1240),
|
SCREENSHOT_SAVED_TO_WORK_PROFILE(1240);
|
||||||
@UiEvent(doc = "Notes application triggered the screenshot for notes")
|
|
||||||
SCREENSHOT_FOR_NOTE_TRIGGERED(1308),
|
|
||||||
@UiEvent(doc = "User accepted the screenshot to be sent to the notes app")
|
|
||||||
SCREENSHOT_FOR_NOTE_ACCEPTED(1309),
|
|
||||||
@UiEvent(doc = "User cancelled the screenshot for notes app flow")
|
|
||||||
SCREENSHOT_FOR_NOTE_CANCELLED(1310);
|
|
||||||
|
|
||||||
private final int mId;
|
private final int mId;
|
||||||
|
|
||||||
|
|||||||
@@ -14,15 +14,15 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.systemui.screenshot;
|
package com.android.systemui.screenshot.appclips;
|
||||||
|
|
||||||
import static com.android.systemui.screenshot.AppClipsTrampolineActivity.ACTION_FINISH_FROM_TRAMPOLINE;
|
import static com.android.systemui.screenshot.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_ACCEPTED;
|
||||||
import static com.android.systemui.screenshot.AppClipsTrampolineActivity.EXTRA_CALLING_PACKAGE_NAME;
|
import static com.android.systemui.screenshot.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_CANCELLED;
|
||||||
import static com.android.systemui.screenshot.AppClipsTrampolineActivity.EXTRA_RESULT_RECEIVER;
|
import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.ACTION_FINISH_FROM_TRAMPOLINE;
|
||||||
import static com.android.systemui.screenshot.AppClipsTrampolineActivity.EXTRA_SCREENSHOT_URI;
|
import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.EXTRA_CALLING_PACKAGE_NAME;
|
||||||
import static com.android.systemui.screenshot.AppClipsTrampolineActivity.PERMISSION_SELF;
|
import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.EXTRA_RESULT_RECEIVER;
|
||||||
import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_FOR_NOTE_ACCEPTED;
|
import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.EXTRA_SCREENSHOT_URI;
|
||||||
import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_FOR_NOTE_CANCELLED;
|
import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.PERMISSION_SELF;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
@@ -52,6 +52,8 @@ import com.android.internal.logging.UiEventLogger;
|
|||||||
import com.android.internal.logging.UiEventLogger.UiEventEnum;
|
import com.android.internal.logging.UiEventLogger.UiEventEnum;
|
||||||
import com.android.settingslib.Utils;
|
import com.android.settingslib.Utils;
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
|
import com.android.systemui.screenshot.CropView;
|
||||||
|
import com.android.systemui.screenshot.MagnifierView;
|
||||||
import com.android.systemui.settings.UserTracker;
|
import com.android.systemui.settings.UserTracker;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|||||||
@@ -32,12 +32,12 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
/** An intermediary singleton object to help communicating with the cross process service. */
|
/** An intermediary singleton object to help communicating with the cross process service. */
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
public class AppClipsCrossProcessHelper {
|
class AppClipsCrossProcessHelper {
|
||||||
|
|
||||||
private final ServiceConnector<IAppClipsScreenshotHelperService> mProxyConnector;
|
private final ServiceConnector<IAppClipsScreenshotHelperService> mProxyConnector;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public AppClipsCrossProcessHelper(@Application Context context) {
|
AppClipsCrossProcessHelper(@Application Context context) {
|
||||||
mProxyConnector = new ServiceConnector.Impl<IAppClipsScreenshotHelperService>(context,
|
mProxyConnector = new ServiceConnector.Impl<IAppClipsScreenshotHelperService>(context,
|
||||||
new Intent(context, AppClipsScreenshotHelperService.class),
|
new Intent(context, AppClipsScreenshotHelperService.class),
|
||||||
Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY
|
Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY
|
||||||
@@ -52,7 +52,7 @@ public class AppClipsCrossProcessHelper {
|
|||||||
* pass around but not a {@link Bitmap}.
|
* pass around but not a {@link Bitmap}.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public Bitmap takeScreenshot() {
|
Bitmap takeScreenshot() {
|
||||||
try {
|
try {
|
||||||
AndroidFuture<ScreenshotHardwareBufferInternal> future =
|
AndroidFuture<ScreenshotHardwareBufferInternal> future =
|
||||||
mProxyConnector.postForResult(
|
mProxyConnector.postForResult(
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.systemui.screenshot.appclips;
|
||||||
|
|
||||||
|
import com.android.internal.logging.UiEvent;
|
||||||
|
import com.android.internal.logging.UiEventLogger;
|
||||||
|
|
||||||
|
enum AppClipsEvent implements UiEventLogger.UiEventEnum {
|
||||||
|
|
||||||
|
@UiEvent(doc = "Notes application triggered the screenshot for notes")
|
||||||
|
SCREENSHOT_FOR_NOTE_TRIGGERED(1308),
|
||||||
|
@UiEvent(doc = "User accepted the screenshot to be sent to the notes app")
|
||||||
|
SCREENSHOT_FOR_NOTE_ACCEPTED(1309),
|
||||||
|
@UiEvent(doc = "User cancelled the screenshot for notes app flow")
|
||||||
|
SCREENSHOT_FOR_NOTE_CANCELLED(1310);
|
||||||
|
|
||||||
|
private final int mId;
|
||||||
|
|
||||||
|
AppClipsEvent(int id) {
|
||||||
|
mId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return mId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,7 +24,6 @@ import android.window.ScreenCapture.ScreenshotSync;
|
|||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.systemui.screenshot.AppClipsActivity;
|
|
||||||
import com.android.wm.shell.bubbles.Bubbles;
|
import com.android.wm.shell.bubbles.Bubbles;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.systemui.screenshot;
|
package com.android.systemui.screenshot.appclips;
|
||||||
|
|
||||||
import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_BLOCKED_BY_ADMIN;
|
import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_BLOCKED_BY_ADMIN;
|
||||||
import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_FAILED;
|
import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_FAILED;
|
||||||
@@ -24,7 +24,7 @@ import static android.content.Intent.EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE;
|
|||||||
import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
|
import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
|
||||||
|
|
||||||
import static com.android.systemui.flags.Flags.SCREENSHOT_APP_CLIPS;
|
import static com.android.systemui.flags.Flags.SCREENSHOT_APP_CLIPS;
|
||||||
import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_FOR_NOTE_TRIGGERED;
|
import static com.android.systemui.screenshot.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_TRIGGERED;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
|
|||||||
@@ -14,12 +14,10 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.systemui.screenshot;
|
package com.android.systemui.screenshot.appclips;
|
||||||
|
|
||||||
import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_FAILED;
|
import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_FAILED;
|
||||||
|
|
||||||
import static androidx.annotation.VisibleForTesting.PACKAGE_PRIVATE;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.HardwareRenderer;
|
import android.graphics.HardwareRenderer;
|
||||||
@@ -31,7 +29,6 @@ import android.net.Uri;
|
|||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.VisibleForTesting;
|
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
import androidx.lifecycle.ViewModel;
|
import androidx.lifecycle.ViewModel;
|
||||||
@@ -39,11 +36,10 @@ import androidx.lifecycle.ViewModelProvider;
|
|||||||
|
|
||||||
import com.android.systemui.dagger.qualifiers.Background;
|
import com.android.systemui.dagger.qualifiers.Background;
|
||||||
import com.android.systemui.dagger.qualifiers.Main;
|
import com.android.systemui.dagger.qualifiers.Main;
|
||||||
import com.android.systemui.screenshot.appclips.AppClipsCrossProcessHelper;
|
import com.android.systemui.screenshot.ImageExporter;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CancellationException;
|
import java.util.concurrent.CancellationException;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
@@ -52,8 +48,7 @@ import java.util.concurrent.Executor;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
/** A {@link ViewModel} to help with the App Clips screenshot flow. */
|
/** A {@link ViewModel} to help with the App Clips screenshot flow. */
|
||||||
@VisibleForTesting(otherwise = PACKAGE_PRIVATE)
|
final class AppClipsViewModel extends ViewModel {
|
||||||
public final class AppClipsViewModel extends ViewModel {
|
|
||||||
|
|
||||||
private final AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
|
private final AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
|
||||||
private final ImageExporter mImageExporter;
|
private final ImageExporter mImageExporter;
|
||||||
@@ -80,8 +75,7 @@ public final class AppClipsViewModel extends ViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Grabs a screenshot and updates the {@link Bitmap} set in screenshot {@link LiveData}. */
|
/** Grabs a screenshot and updates the {@link Bitmap} set in screenshot {@link LiveData}. */
|
||||||
@VisibleForTesting(otherwise = PACKAGE_PRIVATE)
|
void performScreenshot() {
|
||||||
public void performScreenshot() {
|
|
||||||
mBgExecutor.execute(() -> {
|
mBgExecutor.execute(() -> {
|
||||||
Bitmap screenshot = mAppClipsCrossProcessHelper.takeScreenshot();
|
Bitmap screenshot = mAppClipsCrossProcessHelper.takeScreenshot();
|
||||||
mMainExecutor.execute(() -> {
|
mMainExecutor.execute(() -> {
|
||||||
@@ -95,14 +89,12 @@ public final class AppClipsViewModel extends ViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a {@link LiveData} that holds the captured screenshot. */
|
/** Returns a {@link LiveData} that holds the captured screenshot. */
|
||||||
@VisibleForTesting(otherwise = PACKAGE_PRIVATE)
|
LiveData<Bitmap> getScreenshot() {
|
||||||
public LiveData<Bitmap> getScreenshot() {
|
|
||||||
return mScreenshotLiveData;
|
return mScreenshotLiveData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a {@link LiveData} that holds the {@link Uri} where screenshot is saved. */
|
/** Returns a {@link LiveData} that holds the {@link Uri} where screenshot is saved. */
|
||||||
@VisibleForTesting(otherwise = PACKAGE_PRIVATE)
|
LiveData<Uri> getResultLiveData() {
|
||||||
public LiveData<Uri> getResultLiveData() {
|
|
||||||
return mResultLiveData;
|
return mResultLiveData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,8 +102,7 @@ public final class AppClipsViewModel extends ViewModel {
|
|||||||
* Returns a {@link LiveData} that holds the error codes for
|
* Returns a {@link LiveData} that holds the error codes for
|
||||||
* {@link Intent#EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE}.
|
* {@link Intent#EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE}.
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting(otherwise = PACKAGE_PRIVATE)
|
LiveData<Integer> getErrorLiveData() {
|
||||||
public LiveData<Integer> getErrorLiveData() {
|
|
||||||
return mErrorLiveData;
|
return mErrorLiveData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,8 +110,7 @@ public final class AppClipsViewModel extends ViewModel {
|
|||||||
* Saves the provided {@link Drawable} to storage then informs the result {@link Uri} to
|
* Saves the provided {@link Drawable} to storage then informs the result {@link Uri} to
|
||||||
* {@link LiveData}.
|
* {@link LiveData}.
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting(otherwise = PACKAGE_PRIVATE)
|
void saveScreenshotThenFinish(Drawable screenshotDrawable, Rect bounds) {
|
||||||
public void saveScreenshotThenFinish(Drawable screenshotDrawable, Rect bounds) {
|
|
||||||
mBgExecutor.execute(() -> {
|
mBgExecutor.execute(() -> {
|
||||||
// Render the screenshot bitmap in background.
|
// Render the screenshot bitmap in background.
|
||||||
Bitmap screenshotBitmap = renderBitmap(screenshotDrawable, bounds);
|
Bitmap screenshotBitmap = renderBitmap(screenshotDrawable, bounds);
|
||||||
@@ -128,7 +118,7 @@ public final class AppClipsViewModel extends ViewModel {
|
|||||||
// Export and save the screenshot in background.
|
// Export and save the screenshot in background.
|
||||||
// TODO(b/267310185): Save to work profile UserHandle.
|
// TODO(b/267310185): Save to work profile UserHandle.
|
||||||
ListenableFuture<ImageExporter.Result> exportFuture = mImageExporter.export(
|
ListenableFuture<ImageExporter.Result> exportFuture = mImageExporter.export(
|
||||||
mBgExecutor, UUID.randomUUID(), screenshotBitmap, ZonedDateTime.now(),
|
mBgExecutor, UUID.randomUUID(), screenshotBitmap,
|
||||||
Process.myUserHandle());
|
Process.myUserHandle());
|
||||||
|
|
||||||
// Get the result and update state on main thread.
|
// Get the result and update state on main thread.
|
||||||
@@ -160,8 +150,7 @@ public final class AppClipsViewModel extends ViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Helper factory to help with injecting {@link AppClipsViewModel}. */
|
/** Helper factory to help with injecting {@link AppClipsViewModel}. */
|
||||||
@VisibleForTesting(otherwise = PACKAGE_PRIVATE)
|
static final class Factory implements ViewModelProvider.Factory {
|
||||||
public static final class Factory implements ViewModelProvider.Factory {
|
|
||||||
|
|
||||||
private final AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
|
private final AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
|
||||||
private final ImageExporter mImageExporter;
|
private final ImageExporter mImageExporter;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import android.window.ScreenCapture.ScreenshotHardwareBuffer;
|
|||||||
* An internal version of {@link ScreenshotHardwareBuffer} that helps with parceling the information
|
* An internal version of {@link ScreenshotHardwareBuffer} that helps with parceling the information
|
||||||
* necessary for creating a {@link Bitmap}.
|
* necessary for creating a {@link Bitmap}.
|
||||||
*/
|
*/
|
||||||
public class ScreenshotHardwareBufferInternal implements Parcelable {
|
class ScreenshotHardwareBufferInternal implements Parcelable {
|
||||||
|
|
||||||
public static final Creator<ScreenshotHardwareBufferInternal> CREATOR =
|
public static final Creator<ScreenshotHardwareBufferInternal> CREATOR =
|
||||||
new Creator<>() {
|
new Creator<>() {
|
||||||
@@ -45,7 +45,7 @@ public class ScreenshotHardwareBufferInternal implements Parcelable {
|
|||||||
private final HardwareBuffer mHardwareBuffer;
|
private final HardwareBuffer mHardwareBuffer;
|
||||||
private final ParcelableColorSpace mParcelableColorSpace;
|
private final ParcelableColorSpace mParcelableColorSpace;
|
||||||
|
|
||||||
public ScreenshotHardwareBufferInternal(
|
ScreenshotHardwareBufferInternal(
|
||||||
ScreenshotHardwareBuffer screenshotHardwareBuffer) {
|
ScreenshotHardwareBuffer screenshotHardwareBuffer) {
|
||||||
mHardwareBuffer = screenshotHardwareBuffer.getHardwareBuffer();
|
mHardwareBuffer = screenshotHardwareBuffer.getHardwareBuffer();
|
||||||
mParcelableColorSpace = new ParcelableColorSpace(
|
mParcelableColorSpace = new ParcelableColorSpace(
|
||||||
@@ -65,7 +65,7 @@ public class ScreenshotHardwareBufferInternal implements Parcelable {
|
|||||||
* {@link Bitmap#wrapHardwareBuffer(HardwareBuffer, ColorSpace)} and
|
* {@link Bitmap#wrapHardwareBuffer(HardwareBuffer, ColorSpace)} and
|
||||||
* {@link HardwareBuffer#close()} for more information.
|
* {@link HardwareBuffer#close()} for more information.
|
||||||
*/
|
*/
|
||||||
public Bitmap createBitmapThenCloseBuffer() {
|
Bitmap createBitmapThenCloseBuffer() {
|
||||||
Bitmap bitmap = Bitmap.wrapHardwareBuffer(mHardwareBuffer,
|
Bitmap bitmap = Bitmap.wrapHardwareBuffer(mHardwareBuffer,
|
||||||
mParcelableColorSpace.getColorSpace());
|
mParcelableColorSpace.getColorSpace());
|
||||||
mHardwareBuffer.close();
|
mHardwareBuffer.close();
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ package com.android.systemui.screenshot.appclips;
|
|||||||
|
|
||||||
import static android.app.Activity.RESULT_OK;
|
import static android.app.Activity.RESULT_OK;
|
||||||
|
|
||||||
import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_FOR_NOTE_ACCEPTED;
|
import static com.android.systemui.screenshot.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_ACCEPTED;
|
||||||
import static com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_FOR_NOTE_CANCELLED;
|
import static com.android.systemui.screenshot.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_CANCELLED;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.doAnswer;
|
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@@ -34,36 +34,35 @@ import android.content.pm.ApplicationInfo;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PackageManager.ApplicationInfoFlags;
|
import android.content.pm.PackageManager.ApplicationInfoFlags;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.ResultReceiver;
|
import android.os.ResultReceiver;
|
||||||
|
import android.os.UserHandle;
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
import androidx.lifecycle.MutableLiveData;
|
|
||||||
import androidx.test.rule.ActivityTestRule;
|
import androidx.test.rule.ActivityTestRule;
|
||||||
import androidx.test.runner.intercepting.SingleActivityFactory;
|
import androidx.test.runner.intercepting.SingleActivityFactory;
|
||||||
|
|
||||||
import com.android.internal.logging.UiEventLogger;
|
import com.android.internal.logging.UiEventLogger;
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
import com.android.systemui.screenshot.AppClipsActivity;
|
import com.android.systemui.screenshot.ImageExporter;
|
||||||
import com.android.systemui.screenshot.AppClipsTrampolineActivity;
|
|
||||||
import com.android.systemui.screenshot.AppClipsViewModel;
|
|
||||||
import com.android.systemui.settings.UserTracker;
|
import com.android.systemui.settings.UserTracker;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.Futures;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
@RunWith(AndroidTestingRunner.class)
|
@RunWith(AndroidTestingRunner.class)
|
||||||
@@ -78,18 +77,16 @@ public final class AppClipsActivityTest extends SysuiTestCase {
|
|||||||
private static final String TEST_CALLING_PACKAGE = "test-calling-package";
|
private static final String TEST_CALLING_PACKAGE = "test-calling-package";
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private AppClipsViewModel.Factory mViewModelFactory;
|
private AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
|
||||||
|
@Mock
|
||||||
|
private ImageExporter mImageExporter;
|
||||||
@Mock
|
@Mock
|
||||||
private PackageManager mPackageManager;
|
private PackageManager mPackageManager;
|
||||||
@Mock
|
@Mock
|
||||||
private UserTracker mUserTracker;
|
private UserTracker mUserTracker;
|
||||||
@Mock
|
@Mock
|
||||||
private UiEventLogger mUiEventLogger;
|
private UiEventLogger mUiEventLogger;
|
||||||
@Mock
|
|
||||||
private AppClipsViewModel mViewModel;
|
|
||||||
|
|
||||||
private MutableLiveData<Bitmap> mScreenshotLiveData;
|
|
||||||
private MutableLiveData<Uri> mResultLiveData;
|
|
||||||
private AppClipsActivity mActivity;
|
private AppClipsActivity mActivity;
|
||||||
|
|
||||||
// Using the deprecated ActivityTestRule and SingleActivityFactory to help with injecting mocks.
|
// Using the deprecated ActivityTestRule and SingleActivityFactory to help with injecting mocks.
|
||||||
@@ -97,8 +94,11 @@ public final class AppClipsActivityTest extends SysuiTestCase {
|
|||||||
new SingleActivityFactory<>(AppClipsActivityTestable.class) {
|
new SingleActivityFactory<>(AppClipsActivityTestable.class) {
|
||||||
@Override
|
@Override
|
||||||
protected AppClipsActivityTestable create(Intent unUsed) {
|
protected AppClipsActivityTestable create(Intent unUsed) {
|
||||||
return new AppClipsActivityTestable(mViewModelFactory, mPackageManager,
|
return new AppClipsActivityTestable(
|
||||||
mUserTracker, mUiEventLogger);
|
new AppClipsViewModel.Factory(mAppClipsCrossProcessHelper,
|
||||||
|
mImageExporter, getContext().getMainExecutor(),
|
||||||
|
directExecutor()), mPackageManager, mUserTracker,
|
||||||
|
mUiEventLogger);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -110,29 +110,17 @@ public final class AppClipsActivityTest extends SysuiTestCase {
|
|||||||
public void setUp() throws PackageManager.NameNotFoundException {
|
public void setUp() throws PackageManager.NameNotFoundException {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
mScreenshotLiveData = new MutableLiveData<>();
|
|
||||||
mResultLiveData = new MutableLiveData<>();
|
|
||||||
MutableLiveData<Integer> errorLiveData = new MutableLiveData<>();
|
|
||||||
|
|
||||||
when(mViewModelFactory.create(any(Class.class))).thenReturn(mViewModel);
|
|
||||||
when(mViewModel.getScreenshot()).thenReturn(mScreenshotLiveData);
|
|
||||||
when(mViewModel.getResultLiveData()).thenReturn(mResultLiveData);
|
|
||||||
when(mViewModel.getErrorLiveData()).thenReturn(errorLiveData);
|
|
||||||
when(mUserTracker.getUserId()).thenReturn(TEST_USER_ID);
|
when(mUserTracker.getUserId()).thenReturn(TEST_USER_ID);
|
||||||
|
|
||||||
ApplicationInfo applicationInfo = new ApplicationInfo();
|
ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||||
applicationInfo.uid = TEST_UID;
|
applicationInfo.uid = TEST_UID;
|
||||||
when(mPackageManager.getApplicationInfoAsUser(eq(TEST_CALLING_PACKAGE),
|
when(mPackageManager.getApplicationInfoAsUser(eq(TEST_CALLING_PACKAGE),
|
||||||
any(ApplicationInfoFlags.class), eq(TEST_USER_ID))).thenReturn(applicationInfo);
|
any(ApplicationInfoFlags.class), eq(TEST_USER_ID))).thenReturn(applicationInfo);
|
||||||
|
|
||||||
doAnswer(invocation -> {
|
when(mAppClipsCrossProcessHelper.takeScreenshot()).thenReturn(TEST_BITMAP);
|
||||||
runOnMainThread(() -> mScreenshotLiveData.setValue(TEST_BITMAP));
|
ImageExporter.Result result = new ImageExporter.Result();
|
||||||
return null;
|
result.uri = TEST_URI;
|
||||||
}).when(mViewModel).performScreenshot();
|
when(mImageExporter.export(any(Executor.class), any(UUID.class), any(Bitmap.class),
|
||||||
doAnswer(invocation -> {
|
any(UserHandle.class))).thenReturn(Futures.immediateFuture(result));
|
||||||
runOnMainThread(() -> mResultLiveData.setValue(TEST_URI));
|
|
||||||
return null;
|
|
||||||
}).when(mViewModel).saveScreenshotThenFinish(any(Drawable.class), any(Rect.class));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@@ -140,7 +128,6 @@ public final class AppClipsActivityTest extends SysuiTestCase {
|
|||||||
mActivityRule.finishActivity();
|
mActivityRule.finishActivity();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("b/269403503")
|
|
||||||
@Test
|
@Test
|
||||||
public void appClipsLaunched_screenshotDisplayed() {
|
public void appClipsLaunched_screenshotDisplayed() {
|
||||||
launchActivity();
|
launchActivity();
|
||||||
@@ -148,7 +135,6 @@ public final class AppClipsActivityTest extends SysuiTestCase {
|
|||||||
assertThat(((ImageView) mActivity.findViewById(R.id.preview)).getDrawable()).isNotNull();
|
assertThat(((ImageView) mActivity.findViewById(R.id.preview)).getDrawable()).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("b/269403503")
|
|
||||||
@Test
|
@Test
|
||||||
public void screenshotDisplayed_userConsented_screenshotExportedSuccessfully() {
|
public void screenshotDisplayed_userConsented_screenshotExportedSuccessfully() {
|
||||||
ResultReceiver resultReceiver = createResultReceiver((resultCode, data) -> {
|
ResultReceiver resultReceiver = createResultReceiver((resultCode, data) -> {
|
||||||
@@ -168,7 +154,6 @@ public final class AppClipsActivityTest extends SysuiTestCase {
|
|||||||
verify(mUiEventLogger).log(SCREENSHOT_FOR_NOTE_ACCEPTED, TEST_UID, TEST_CALLING_PACKAGE);
|
verify(mUiEventLogger).log(SCREENSHOT_FOR_NOTE_ACCEPTED, TEST_UID, TEST_CALLING_PACKAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("b/269403503")
|
|
||||||
@Test
|
@Test
|
||||||
public void screenshotDisplayed_userDeclined() {
|
public void screenshotDisplayed_userDeclined() {
|
||||||
ResultReceiver resultReceiver = createResultReceiver((resultCode, data) -> {
|
ResultReceiver resultReceiver = createResultReceiver((resultCode, data) -> {
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_WINDOW_MODE_UNSUPP
|
|||||||
import static android.content.Intent.EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE;
|
import static android.content.Intent.EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE;
|
||||||
|
|
||||||
import static com.android.systemui.flags.Flags.SCREENSHOT_APP_CLIPS;
|
import static com.android.systemui.flags.Flags.SCREENSHOT_APP_CLIPS;
|
||||||
import static com.android.systemui.screenshot.AppClipsTrampolineActivity.EXTRA_SCREENSHOT_URI;
|
import static com.android.systemui.screenshot.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_TRIGGERED;
|
||||||
|
import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.EXTRA_SCREENSHOT_URI;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
@@ -59,8 +60,6 @@ import com.android.systemui.SysuiTestCase;
|
|||||||
import com.android.systemui.dagger.qualifiers.Main;
|
import com.android.systemui.dagger.qualifiers.Main;
|
||||||
import com.android.systemui.flags.FeatureFlags;
|
import com.android.systemui.flags.FeatureFlags;
|
||||||
import com.android.systemui.notetask.NoteTaskController;
|
import com.android.systemui.notetask.NoteTaskController;
|
||||||
import com.android.systemui.screenshot.AppClipsTrampolineActivity;
|
|
||||||
import com.android.systemui.screenshot.ScreenshotEvent;
|
|
||||||
import com.android.systemui.settings.UserTracker;
|
import com.android.systemui.settings.UserTracker;
|
||||||
import com.android.wm.shell.bubbles.Bubbles;
|
import com.android.wm.shell.bubbles.Bubbles;
|
||||||
|
|
||||||
@@ -262,8 +261,7 @@ public final class AppClipsTrampolineActivityTest extends SysuiTestCase {
|
|||||||
mActivityRule.launchActivity(mActivityIntent);
|
mActivityRule.launchActivity(mActivityIntent);
|
||||||
waitForIdleSync();
|
waitForIdleSync();
|
||||||
|
|
||||||
verify(mUiEventLogger).log(ScreenshotEvent.SCREENSHOT_FOR_NOTE_TRIGGERED, TEST_UID,
|
verify(mUiEventLogger).log(SCREENSHOT_FOR_NOTE_TRIGGERED, TEST_UID, TEST_CALLING_PACKAGE);
|
||||||
TEST_CALLING_PACKAGE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void mockToSatisfyAllPrerequisites() throws NameNotFoundException {
|
private void mockToSatisfyAllPrerequisites() throws NameNotFoundException {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.systemui.screenshot;
|
package com.android.systemui.screenshot.appclips;
|
||||||
|
|
||||||
import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_FAILED;
|
import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_FAILED;
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ import android.os.UserHandle;
|
|||||||
import androidx.test.runner.AndroidJUnit4;
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
import com.android.systemui.screenshot.appclips.AppClipsCrossProcessHelper;
|
import com.android.systemui.screenshot.ImageExporter;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.Futures;
|
import com.google.common.util.concurrent.Futures;
|
||||||
|
|
||||||
@@ -46,7 +46,6 @@ import org.junit.runner.RunWith;
|
|||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
@@ -62,7 +61,7 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
|
|||||||
@Mock private AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
|
@Mock private AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
|
||||||
@Mock private ImageExporter mImageExporter;
|
@Mock private ImageExporter mImageExporter;
|
||||||
|
|
||||||
private com.android.systemui.screenshot.AppClipsViewModel mViewModel;
|
private AppClipsViewModel mViewModel;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@@ -99,8 +98,8 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void saveScreenshot_throwsError_shouldUpdateErrorWithFailed() {
|
public void saveScreenshot_throwsError_shouldUpdateErrorWithFailed() {
|
||||||
when(mImageExporter.export(any(Executor.class), any(UUID.class), eq(null), any(
|
when(mImageExporter.export(any(Executor.class), any(UUID.class), eq(null),
|
||||||
ZonedDateTime.class), any(UserHandle.class))).thenReturn(
|
any(UserHandle.class))).thenReturn(
|
||||||
Futures.immediateFailedFuture(new ExecutionException(new Throwable())));
|
Futures.immediateFailedFuture(new ExecutionException(new Throwable())));
|
||||||
|
|
||||||
mViewModel.saveScreenshotThenFinish(FAKE_DRAWABLE, FAKE_RECT);
|
mViewModel.saveScreenshotThenFinish(FAKE_DRAWABLE, FAKE_RECT);
|
||||||
@@ -113,9 +112,9 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void saveScreenshot_failsSilently_shouldUpdateErrorWithFailed() {
|
public void saveScreenshot_failsSilently_shouldUpdateErrorWithFailed() {
|
||||||
when(mImageExporter.export(any(Executor.class), any(UUID.class), eq(null), any(
|
when(mImageExporter.export(any(Executor.class), any(UUID.class), eq(null),
|
||||||
ZonedDateTime.class), any(UserHandle.class))).thenReturn(
|
any(UserHandle.class))).thenReturn(
|
||||||
Futures.immediateFuture(new ImageExporter.Result()));
|
Futures.immediateFuture(new ImageExporter.Result()));
|
||||||
|
|
||||||
mViewModel.saveScreenshotThenFinish(FAKE_DRAWABLE, FAKE_RECT);
|
mViewModel.saveScreenshotThenFinish(FAKE_DRAWABLE, FAKE_RECT);
|
||||||
waitForIdleSync();
|
waitForIdleSync();
|
||||||
@@ -129,9 +128,8 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
|
|||||||
public void saveScreenshot_succeeds_shouldUpdateResultWithUri() {
|
public void saveScreenshot_succeeds_shouldUpdateResultWithUri() {
|
||||||
ImageExporter.Result result = new ImageExporter.Result();
|
ImageExporter.Result result = new ImageExporter.Result();
|
||||||
result.uri = FAKE_URI;
|
result.uri = FAKE_URI;
|
||||||
when(mImageExporter.export(any(Executor.class), any(UUID.class), eq(null), any(
|
when(mImageExporter.export(any(Executor.class), any(UUID.class), eq(null),
|
||||||
ZonedDateTime.class), any(UserHandle.class))).thenReturn(
|
any(UserHandle.class))).thenReturn(Futures.immediateFuture(result));
|
||||||
Futures.immediateFuture(result));
|
|
||||||
|
|
||||||
mViewModel.saveScreenshotThenFinish(FAKE_DRAWABLE, FAKE_RECT);
|
mViewModel.saveScreenshotThenFinish(FAKE_DRAWABLE, FAKE_RECT);
|
||||||
waitForIdleSync();
|
waitForIdleSync();
|
||||||
|
|||||||
Reference in New Issue
Block a user