Merge "Implement work profile considerations in app clips" into udc-dev am: 5d63998d8f
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22930877 Change-Id: Icf3923c3b0c7c41762ce625179bfd7648176b3bd Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -293,10 +293,9 @@ public class ImageExporter {
|
|||||||
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()) {
|
Uri uriWithUserId = ContentProvider.maybeAddUserId(baseUri, owner.getIdentifier());
|
||||||
baseUri = ContentProvider.maybeAddUserId(baseUri, owner.getIdentifier());
|
|
||||||
}
|
Uri uri = resolver.insert(uriWithUserId, values);
|
||||||
Uri uri = resolver.insert(baseUri, values);
|
|
||||||
if (uri == null) {
|
if (uri == null) {
|
||||||
throw new ImageExportException(RESOLVER_INSERT_RETURNED_NULL);
|
throw new ImageExportException(RESOLVER_INSERT_RETURNED_NULL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ public class AppClipsActivity extends ComponentActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateImageDimensions();
|
updateImageDimensions();
|
||||||
mViewModel.saveScreenshotThenFinish(drawable, bounds);
|
mViewModel.saveScreenshotThenFinish(drawable, bounds, getUser());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setResultThenFinish(Uri uri) {
|
private void setResultThenFinish(Uri uri) {
|
||||||
@@ -255,6 +255,11 @@ public class AppClipsActivity extends ComponentActivity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Grant permission here instead of in the trampoline activity because this activity can run
|
||||||
|
// as work profile user so the URI can belong to the work profile user while the trampoline
|
||||||
|
// activity always runs as main user.
|
||||||
|
grantUriPermission(mCallingPackageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
|
||||||
Bundle data = new Bundle();
|
Bundle data = new Bundle();
|
||||||
data.putInt(Intent.EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE,
|
data.putInt(Intent.EXTRA_CAPTURE_CONTENT_FOR_NOTE_STATUS_CODE,
|
||||||
Intent.CAPTURE_CONTENT_FOR_NOTE_SUCCESS);
|
Intent.CAPTURE_CONTENT_FOR_NOTE_SUCCESS);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ package com.android.systemui.screenshot.appclips;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.view.Display;
|
import android.os.UserManager;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
@@ -27,6 +27,7 @@ import com.android.internal.infra.AndroidFuture;
|
|||||||
import com.android.internal.infra.ServiceConnector;
|
import com.android.internal.infra.ServiceConnector;
|
||||||
import com.android.systemui.dagger.SysUISingleton;
|
import com.android.systemui.dagger.SysUISingleton;
|
||||||
import com.android.systemui.dagger.qualifiers.Application;
|
import com.android.systemui.dagger.qualifiers.Application;
|
||||||
|
import com.android.systemui.settings.DisplayTracker;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@@ -35,14 +36,20 @@ import javax.inject.Inject;
|
|||||||
class AppClipsCrossProcessHelper {
|
class AppClipsCrossProcessHelper {
|
||||||
|
|
||||||
private final ServiceConnector<IAppClipsScreenshotHelperService> mProxyConnector;
|
private final ServiceConnector<IAppClipsScreenshotHelperService> mProxyConnector;
|
||||||
|
private final DisplayTracker mDisplayTracker;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
AppClipsCrossProcessHelper(@Application Context context) {
|
AppClipsCrossProcessHelper(@Application Context context, UserManager userManager,
|
||||||
mProxyConnector = new ServiceConnector.Impl<IAppClipsScreenshotHelperService>(context,
|
DisplayTracker displayTracker) {
|
||||||
|
// Start a service as main user so that even if the app clips activity is running as work
|
||||||
|
// profile user the service is able to use correct instance of Bubbles to grab a screenshot
|
||||||
|
// excluding the bubble layer.
|
||||||
|
mProxyConnector = new ServiceConnector.Impl<>(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
|
||||||
| Context.BIND_NOT_VISIBLE, context.getUserId(),
|
| Context.BIND_NOT_VISIBLE, userManager.getMainUser().getIdentifier(),
|
||||||
IAppClipsScreenshotHelperService.Stub::asInterface);
|
IAppClipsScreenshotHelperService.Stub::asInterface);
|
||||||
|
mDisplayTracker = displayTracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,7 +63,9 @@ class AppClipsCrossProcessHelper {
|
|||||||
try {
|
try {
|
||||||
AndroidFuture<ScreenshotHardwareBufferInternal> future =
|
AndroidFuture<ScreenshotHardwareBufferInternal> future =
|
||||||
mProxyConnector.postForResult(
|
mProxyConnector.postForResult(
|
||||||
service -> service.takeScreenshot(Display.DEFAULT_DISPLAY));
|
service ->
|
||||||
|
// Take a screenshot of the default display of the user.
|
||||||
|
service.takeScreenshot(mDisplayTracker.getDefaultDisplayId()));
|
||||||
return future.get().createBitmapThenCloseBuffer();
|
return future.get().createBitmapThenCloseBuffer();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_FAILED;
|
|||||||
import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_SUCCESS;
|
import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_SUCCESS;
|
||||||
import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_WINDOW_MODE_UNSUPPORTED;
|
import static android.content.Intent.CAPTURE_CONTENT_FOR_NOTE_WINDOW_MODE_UNSUPPORTED;
|
||||||
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 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.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_TRIGGERED;
|
import static com.android.systemui.screenshot.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_TRIGGERED;
|
||||||
@@ -34,6 +33,7 @@ import android.content.Intent;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PackageManager.ApplicationInfoFlags;
|
import android.content.pm.PackageManager.ApplicationInfoFlags;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
|
import android.content.pm.UserInfo;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -82,6 +82,8 @@ public class AppClipsTrampolineActivity extends Activity {
|
|||||||
private static final String TAG = AppClipsTrampolineActivity.class.getSimpleName();
|
private static final String TAG = AppClipsTrampolineActivity.class.getSimpleName();
|
||||||
static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
|
static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
|
||||||
static final String EXTRA_SCREENSHOT_URI = TAG + "SCREENSHOT_URI";
|
static final String EXTRA_SCREENSHOT_URI = TAG + "SCREENSHOT_URI";
|
||||||
|
@VisibleForTesting
|
||||||
|
static final String EXTRA_USE_WP_USER = TAG + "USE_WP_USER";
|
||||||
static final String ACTION_FINISH_FROM_TRAMPOLINE = TAG + "FINISH_FROM_TRAMPOLINE";
|
static final String ACTION_FINISH_FROM_TRAMPOLINE = TAG + "FINISH_FROM_TRAMPOLINE";
|
||||||
static final String EXTRA_RESULT_RECEIVER = TAG + "RESULT_RECEIVER";
|
static final String EXTRA_RESULT_RECEIVER = TAG + "RESULT_RECEIVER";
|
||||||
static final String EXTRA_CALLING_PACKAGE_NAME = TAG + "CALLING_PACKAGE_NAME";
|
static final String EXTRA_CALLING_PACKAGE_NAME = TAG + "CALLING_PACKAGE_NAME";
|
||||||
@@ -98,6 +100,7 @@ public class AppClipsTrampolineActivity extends Activity {
|
|||||||
private final ResultReceiver mResultReceiver;
|
private final ResultReceiver mResultReceiver;
|
||||||
|
|
||||||
private Intent mKillAppClipsBroadcastIntent;
|
private Intent mKillAppClipsBroadcastIntent;
|
||||||
|
private UserHandle mNotesAppUser;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public AppClipsTrampolineActivity(DevicePolicyManager devicePolicyManager, FeatureFlags flags,
|
public AppClipsTrampolineActivity(DevicePolicyManager devicePolicyManager, FeatureFlags flags,
|
||||||
@@ -165,15 +168,21 @@ public class AppClipsTrampolineActivity extends Activity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mNotesAppUser = getUser();
|
||||||
|
if (getIntent().getBooleanExtra(EXTRA_USE_WP_USER, /* defaultValue= */ false)) {
|
||||||
|
// Get the work profile user internally instead of passing around via intent extras as
|
||||||
|
// this activity is exported apps could potentially mess around with intent extras.
|
||||||
|
mNotesAppUser = getWorkProfileUser().orElse(mNotesAppUser);
|
||||||
|
}
|
||||||
|
|
||||||
String callingPackageName = getCallingPackage();
|
String callingPackageName = getCallingPackage();
|
||||||
Intent intent = new Intent().setComponent(componentName)
|
Intent intent = new Intent().setComponent(componentName)
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
.putExtra(EXTRA_RESULT_RECEIVER, mResultReceiver)
|
.putExtra(EXTRA_RESULT_RECEIVER, mResultReceiver)
|
||||||
.putExtra(EXTRA_CALLING_PACKAGE_NAME, callingPackageName);
|
.putExtra(EXTRA_CALLING_PACKAGE_NAME, callingPackageName);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Start the App Clips activity.
|
// Start the App Clips activity for the user corresponding to the notes app user.
|
||||||
startActivity(intent);
|
startActivityAsUser(intent, mNotesAppUser);
|
||||||
|
|
||||||
// Set up the broadcast intent that will inform the above App Clips activity to finish
|
// Set up the broadcast intent that will inform the above App Clips activity to finish
|
||||||
// when this trampoline activity is finished.
|
// when this trampoline activity is finished.
|
||||||
@@ -198,6 +207,13 @@ public class AppClipsTrampolineActivity extends Activity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Optional<UserHandle> getWorkProfileUser() {
|
||||||
|
return mUserTracker.getUserProfiles().stream()
|
||||||
|
.filter(profile -> mUserManager.isManagedProfile(profile.id))
|
||||||
|
.findFirst()
|
||||||
|
.map(UserInfo::getUserHandle);
|
||||||
|
}
|
||||||
|
|
||||||
private void maybeStartActivityForWPUser() {
|
private void maybeStartActivityForWPUser() {
|
||||||
UserHandle mainUser = mUserManager.getMainUser();
|
UserHandle mainUser = mUserManager.getMainUser();
|
||||||
if (mainUser == null) {
|
if (mainUser == null) {
|
||||||
@@ -205,9 +221,13 @@ public class AppClipsTrampolineActivity extends Activity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the activity as the main user with activity result forwarding.
|
// Start the activity as the main user with activity result forwarding. Set the intent extra
|
||||||
|
// so that the newly started trampoline activity starts the actual app clips activity as the
|
||||||
|
// work profile user. Starting the app clips activity as the work profile user is required
|
||||||
|
// to save the screenshot in work profile user storage and grant read permission to the URI.
|
||||||
startActivityAsUser(
|
startActivityAsUser(
|
||||||
new Intent(this, AppClipsTrampolineActivity.class)
|
new Intent(this, AppClipsTrampolineActivity.class)
|
||||||
|
.putExtra(EXTRA_USE_WP_USER, /* value= */ true)
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT), mainUser);
|
.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT), mainUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +241,7 @@ public class AppClipsTrampolineActivity extends Activity {
|
|||||||
int callingPackageUid = 0;
|
int callingPackageUid = 0;
|
||||||
try {
|
try {
|
||||||
callingPackageUid = mPackageManager.getApplicationInfoAsUser(callingPackageName,
|
callingPackageUid = mPackageManager.getApplicationInfoAsUser(callingPackageName,
|
||||||
APPLICATION_INFO_FLAGS, mUserTracker.getUserId()).uid;
|
APPLICATION_INFO_FLAGS, mNotesAppUser.getIdentifier()).uid;
|
||||||
} catch (NameNotFoundException e) {
|
} catch (NameNotFoundException e) {
|
||||||
Log.d(TAG, "Couldn't find notes app UID " + e);
|
Log.d(TAG, "Couldn't find notes app UID " + e);
|
||||||
}
|
}
|
||||||
@@ -254,14 +274,14 @@ public class AppClipsTrampolineActivity extends Activity {
|
|||||||
|
|
||||||
if (statusCode == CAPTURE_CONTENT_FOR_NOTE_SUCCESS) {
|
if (statusCode == CAPTURE_CONTENT_FOR_NOTE_SUCCESS) {
|
||||||
Uri uri = resultData.getParcelable(EXTRA_SCREENSHOT_URI, Uri.class);
|
Uri uri = resultData.getParcelable(EXTRA_SCREENSHOT_URI, Uri.class);
|
||||||
convertedData.setData(uri).addFlags(FLAG_GRANT_READ_URI_PERMISSION);
|
convertedData.setData(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Broadcast no longer required, setting it to null.
|
// Broadcast no longer required, setting it to null.
|
||||||
mKillAppClipsBroadcastIntent = null;
|
mKillAppClipsBroadcastIntent = null;
|
||||||
|
|
||||||
// Expand the note bubble before returning the result.
|
// Expand the note bubble before returning the result.
|
||||||
mNoteTaskController.showNoteTask(NoteTaskEntryPoint.APP_CLIPS);
|
mNoteTaskController.showNoteTaskAsUser(NoteTaskEntryPoint.APP_CLIPS, mNotesAppUser);
|
||||||
setResult(RESULT_OK, convertedData);
|
setResult(RESULT_OK, convertedData);
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import android.graphics.Rect;
|
|||||||
import android.graphics.RenderNode;
|
import android.graphics.RenderNode;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Process;
|
import android.os.UserHandle;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
@@ -110,16 +110,14 @@ 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}.
|
||||||
*/
|
*/
|
||||||
void saveScreenshotThenFinish(Drawable screenshotDrawable, Rect bounds) {
|
void saveScreenshotThenFinish(Drawable screenshotDrawable, Rect bounds, UserHandle user) {
|
||||||
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);
|
||||||
|
|
||||||
// Export and save the screenshot in background.
|
// Export and save the screenshot in background.
|
||||||
// TODO(b/267310185): Save to work profile UserHandle.
|
|
||||||
ListenableFuture<ImageExporter.Result> exportFuture = mImageExporter.export(
|
ListenableFuture<ImageExporter.Result> exportFuture = mImageExporter.export(
|
||||||
mBgExecutor, UUID.randomUUID(), screenshotBitmap,
|
mBgExecutor, UUID.randomUUID(), screenshotBitmap, user);
|
||||||
Process.myUserHandle());
|
|
||||||
|
|
||||||
// Get the result and update state on main thread.
|
// Get the result and update state on main thread.
|
||||||
exportFuture.addListener(() -> {
|
exportFuture.addListener(() -> {
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ import android.graphics.Bitmap;
|
|||||||
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.Process;
|
||||||
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;
|
||||||
|
|
||||||
@@ -120,7 +120,8 @@ public final class AppClipsActivityTest extends SysuiTestCase {
|
|||||||
ImageExporter.Result result = new ImageExporter.Result();
|
ImageExporter.Result result = new ImageExporter.Result();
|
||||||
result.uri = TEST_URI;
|
result.uri = TEST_URI;
|
||||||
when(mImageExporter.export(any(Executor.class), any(UUID.class), any(Bitmap.class),
|
when(mImageExporter.export(any(Executor.class), any(UUID.class), any(Bitmap.class),
|
||||||
any(UserHandle.class))).thenReturn(Futures.immediateFuture(result));
|
eq(Process.myUserHandle())))
|
||||||
|
.thenReturn(Futures.immediateFuture(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ 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.appclips.AppClipsEvent.SCREENSHOT_FOR_NOTE_TRIGGERED;
|
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.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.EXTRA_SCREENSHOT_URI;
|
||||||
|
import static com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity.EXTRA_USE_WP_USER;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
@@ -74,6 +75,7 @@ import org.junit.runner.RunWith;
|
|||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@RunWith(AndroidTestingRunner.class)
|
@RunWith(AndroidTestingRunner.class)
|
||||||
@@ -82,7 +84,6 @@ public final class AppClipsTrampolineActivityTest extends SysuiTestCase {
|
|||||||
private static final String TEST_URI_STRING = "www.test-uri.com";
|
private static final String TEST_URI_STRING = "www.test-uri.com";
|
||||||
private static final Uri TEST_URI = Uri.parse(TEST_URI_STRING);
|
private static final Uri TEST_URI = Uri.parse(TEST_URI_STRING);
|
||||||
private static final int TEST_UID = 42;
|
private static final int TEST_UID = 42;
|
||||||
private static final int TEST_USER_ID = 43;
|
|
||||||
private static final String TEST_CALLING_PACKAGE = "test-calling-package";
|
private static final String TEST_CALLING_PACKAGE = "test-calling-package";
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
@@ -287,6 +288,7 @@ public final class AppClipsTrampolineActivityTest extends SysuiTestCase {
|
|||||||
assertThat(actualIntent.getComponent()).isEqualTo(
|
assertThat(actualIntent.getComponent()).isEqualTo(
|
||||||
new ComponentName(mContext, AppClipsTrampolineActivity.class));
|
new ComponentName(mContext, AppClipsTrampolineActivity.class));
|
||||||
assertThat(actualIntent.getFlags()).isEqualTo(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
|
assertThat(actualIntent.getFlags()).isEqualTo(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
|
||||||
|
assertThat(actualIntent.getBooleanExtra(EXTRA_USE_WP_USER, false)).isTrue();
|
||||||
assertThat(activity.mStartingUser).isEqualTo(UserHandle.SYSTEM);
|
assertThat(activity.mStartingUser).isEqualTo(UserHandle.SYSTEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,13 +315,13 @@ public final class AppClipsTrampolineActivityTest extends SysuiTestCase {
|
|||||||
when(mOptionalBubbles.get()).thenReturn(mBubbles);
|
when(mOptionalBubbles.get()).thenReturn(mBubbles);
|
||||||
when(mBubbles.isAppBubbleTaskId(anyInt())).thenReturn(true);
|
when(mBubbles.isAppBubbleTaskId(anyInt())).thenReturn(true);
|
||||||
when(mDevicePolicyManager.getScreenCaptureDisabled(eq(null))).thenReturn(false);
|
when(mDevicePolicyManager.getScreenCaptureDisabled(eq(null))).thenReturn(false);
|
||||||
when(mUserTracker.getUserId()).thenReturn(TEST_USER_ID);
|
when(mUserTracker.getUserProfiles()).thenReturn(List.of());
|
||||||
|
|
||||||
ApplicationInfo testApplicationInfo = new ApplicationInfo();
|
ApplicationInfo testApplicationInfo = new ApplicationInfo();
|
||||||
testApplicationInfo.uid = TEST_UID;
|
testApplicationInfo.uid = TEST_UID;
|
||||||
when(mPackageManager.getApplicationInfoAsUser(eq(TEST_CALLING_PACKAGE),
|
when(mPackageManager.getApplicationInfoAsUser(eq(TEST_CALLING_PACKAGE),
|
||||||
any(ApplicationInfoFlags.class),
|
any(ApplicationInfoFlags.class),
|
||||||
eq(TEST_USER_ID))).thenReturn(testApplicationInfo);
|
eq(mContext.getUser().getIdentifier()))).thenReturn(testApplicationInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class AppClipsTrampolineActivityTestable extends
|
public static final class AppClipsTrampolineActivityTestable extends
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import android.graphics.Rect;
|
|||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.graphics.drawable.ShapeDrawable;
|
import android.graphics.drawable.ShapeDrawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Process;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
|
|
||||||
import androidx.test.runner.AndroidJUnit4;
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
@@ -57,10 +58,10 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
|
|||||||
private static final Drawable FAKE_DRAWABLE = new ShapeDrawable();
|
private static final Drawable FAKE_DRAWABLE = new ShapeDrawable();
|
||||||
private static final Rect FAKE_RECT = new Rect();
|
private static final Rect FAKE_RECT = new Rect();
|
||||||
private static final Uri FAKE_URI = Uri.parse("www.test-uri.com");
|
private static final Uri FAKE_URI = Uri.parse("www.test-uri.com");
|
||||||
|
private static final UserHandle USER_HANDLE = Process.myUserHandle();
|
||||||
|
|
||||||
@Mock private AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
|
@Mock private AppClipsCrossProcessHelper mAppClipsCrossProcessHelper;
|
||||||
@Mock private ImageExporter mImageExporter;
|
@Mock private ImageExporter mImageExporter;
|
||||||
|
|
||||||
private AppClipsViewModel mViewModel;
|
private AppClipsViewModel mViewModel;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -99,10 +100,10 @@ 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),
|
when(mImageExporter.export(any(Executor.class), any(UUID.class), eq(null),
|
||||||
any(UserHandle.class))).thenReturn(
|
eq(USER_HANDLE))).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, USER_HANDLE);
|
||||||
waitForIdleSync();
|
waitForIdleSync();
|
||||||
|
|
||||||
assertThat(mViewModel.getErrorLiveData().getValue())
|
assertThat(mViewModel.getErrorLiveData().getValue())
|
||||||
@@ -113,10 +114,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),
|
when(mImageExporter.export(any(Executor.class), any(UUID.class), eq(null),
|
||||||
any(UserHandle.class))).thenReturn(
|
eq(USER_HANDLE))).thenReturn(Futures.immediateFuture(new ImageExporter.Result()));
|
||||||
Futures.immediateFuture(new ImageExporter.Result()));
|
|
||||||
|
|
||||||
mViewModel.saveScreenshotThenFinish(FAKE_DRAWABLE, FAKE_RECT);
|
mViewModel.saveScreenshotThenFinish(FAKE_DRAWABLE, FAKE_RECT, USER_HANDLE);
|
||||||
waitForIdleSync();
|
waitForIdleSync();
|
||||||
|
|
||||||
assertThat(mViewModel.getErrorLiveData().getValue())
|
assertThat(mViewModel.getErrorLiveData().getValue())
|
||||||
@@ -129,9 +129,9 @@ public final class AppClipsViewModelTest extends SysuiTestCase {
|
|||||||
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),
|
when(mImageExporter.export(any(Executor.class), any(UUID.class), eq(null),
|
||||||
any(UserHandle.class))).thenReturn(Futures.immediateFuture(result));
|
eq(USER_HANDLE))).thenReturn(Futures.immediateFuture(result));
|
||||||
|
|
||||||
mViewModel.saveScreenshotThenFinish(FAKE_DRAWABLE, FAKE_RECT);
|
mViewModel.saveScreenshotThenFinish(FAKE_DRAWABLE, FAKE_RECT, USER_HANDLE);
|
||||||
waitForIdleSync();
|
waitForIdleSync();
|
||||||
|
|
||||||
assertThat(mViewModel.getErrorLiveData().getValue()).isNull();
|
assertThat(mViewModel.getErrorLiveData().getValue()).isNull();
|
||||||
|
|||||||
Reference in New Issue
Block a user