diff options
author | 2022-10-05 14:09:28 +0200 | |
---|---|---|
committer | 2022-10-17 17:45:53 +0200 | |
commit | 7c1be3298d99cde28ac39b3095391065d619eaa8 (patch) | |
tree | 781e79b896625a8a8bf93e96c3e5fa3c8948b38d | |
parent | 0050a51961000057f7858bb2b8892892aaad3232 (diff) |
Add deviceId to Context and allow for creating Contexts with different deviceId.
Applications may create contexts associated with the default host device or with any virtual device. The only way to create a non-default device context for now is via an explcit createDeviceContext call.
Bug: 239152561
Test: atest FrameworksCoreTests:ContextTest
Change-Id: If18dc7661fb232b0bc40121c723673ba880be9d5
-rw-r--r-- | core/api/current.txt | 2 | ||||
-rw-r--r-- | core/java/android/app/ContextImpl.java | 32 | ||||
-rw-r--r-- | core/java/android/content/Context.java | 39 | ||||
-rw-r--r-- | core/java/android/content/ContextWrapper.java | 10 | ||||
-rw-r--r-- | core/tests/coretests/src/android/content/ContextTest.java | 25 | ||||
-rw-r--r-- | test-mock/src/android/test/mock/MockContext.java | 10 |
6 files changed, 118 insertions, 0 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 8138f6abea87..1d679ddafdf2 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -9684,6 +9684,7 @@ package android.content { method public abstract android.content.Context createConfigurationContext(@NonNull android.content.res.Configuration); method @NonNull public android.content.Context createContext(@NonNull android.content.ContextParams); method public abstract android.content.Context createContextForSplit(String) throws android.content.pm.PackageManager.NameNotFoundException; + method @NonNull public android.content.Context createDeviceContext(int); method public abstract android.content.Context createDeviceProtectedStorageContext(); method @DisplayContext public abstract android.content.Context createDisplayContext(@NonNull android.view.Display); method public abstract android.content.Context createPackageContext(String, int) throws android.content.pm.PackageManager.NameNotFoundException; @@ -9714,6 +9715,7 @@ package android.content { method public abstract android.content.ContentResolver getContentResolver(); method public abstract java.io.File getDataDir(); method public abstract java.io.File getDatabasePath(String); + method public int getDeviceId(); method public abstract java.io.File getDir(String, int); method @Nullable public android.view.Display getDisplay(); method @Nullable public final android.graphics.drawable.Drawable getDrawable(@DrawableRes int); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 0e1b47f65561..10cdf5315b55 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -25,6 +25,8 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UiContext; +import android.companion.virtual.VirtualDevice; +import android.companion.virtual.VirtualDeviceManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.AttributionSource; import android.content.AutofillOptions; @@ -241,6 +243,7 @@ class ContextImpl extends Context { @UnsupportedAppUsage private @NonNull Resources mResources; private @Nullable Display mDisplay; // may be null if invalid display or not initialized yet. + private int mDeviceId = VirtualDeviceManager.DEFAULT_DEVICE_ID; /** * If set to {@code true} the resources for this context will be configured for mDisplay which @@ -2700,6 +2703,30 @@ class ContextImpl extends Context { return context; } + @Override + public @NonNull Context createDeviceContext(int deviceId) { + boolean validDeviceId = deviceId == VirtualDeviceManager.DEFAULT_DEVICE_ID; + if (deviceId > VirtualDeviceManager.DEFAULT_DEVICE_ID) { + VirtualDeviceManager vdm = getSystemService(VirtualDeviceManager.class); + if (vdm != null) { + List<VirtualDevice> virtualDevices = vdm.getVirtualDevices(); + validDeviceId = virtualDevices.stream().anyMatch(d -> d.getDeviceId() == deviceId); + } + } + if (!validDeviceId) { + throw new IllegalArgumentException( + "Not a valid ID of the default device or any virtual device: " + deviceId); + } + + ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mParams, + mAttributionSource.getAttributionTag(), + mAttributionSource.getNext(), + mSplitName, mToken, mUser, mFlags, mClassLoader, null); + + context.mDeviceId = deviceId; + return context; + } + @NonNull @Override public WindowContext createWindowContext(@WindowType int type, @@ -2947,6 +2974,11 @@ class ContextImpl extends Context { } @Override + public int getDeviceId() { + return mDeviceId; + } + + @Override public DisplayAdjustments getDisplayAdjustments(int displayId) { return mResources.getDisplayAdjustments(); } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index e28df09e61d7..02cf3e68b20b 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -46,6 +46,7 @@ import android.app.VrManager; import android.app.ambientcontext.AmbientContextManager; import android.app.people.PeopleManager; import android.app.time.TimeManager; +import android.companion.virtual.VirtualDeviceManager; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.compat.annotation.UnsupportedAppUsage; @@ -6829,6 +6830,30 @@ public abstract class Context { public abstract Context createDisplayContext(@NonNull Display display); /** + * Returns a new {@code Context} object from the current context but with device association + * given by the {@code deviceId}. Each call to this method returns a new instance of a context + * object. Context objects are not shared; however, common state (such as the + * {@link ClassLoader} and other resources for the same configuration) can be shared, so the + * {@code Context} itself is lightweight. + * <p> + * Applications that run on virtual devices may use this method to access the default device + * capabilities and functionality (by passing + * {@link android.companion.virtual.VirtualDeviceManager#DEFAULT_DEVICE_ID}. Similarly, + * applications running on the default device may access the functionality of virtual devices. + * </p> + * @param deviceId The ID of the device to associate with this context. + * @return A context associated with the given device ID. + * + * @see #getDeviceId() + * @see VirtualDeviceManager#getVirtualDevices() + * @throws IllegalArgumentException if the given device ID is not a valid ID of the default + * device or a virtual device. + */ + public @NonNull Context createDeviceContext(int deviceId) { + throw new RuntimeException("Not implemented. Must override in a subclass."); + } + + /** * Creates a Context for a non-activity window. * * <p> @@ -7151,6 +7176,20 @@ public abstract class Context { public abstract void updateDisplay(int displayId); /** + * Get the device ID this context is associated with. Applications can use this method to + * determine whether they are running on a virtual device and identify that device. + * + * The device ID of the host device is + * {@link android.companion.virtual.VirtualDeviceManager#DEFAULT_DEVICE_ID} + * + * @return the ID of the device this context is associated with. + * @see #createDeviceContext(int) + */ + public int getDeviceId() { + throw new RuntimeException("Not implemented. Must override in a subclass."); + } + + /** * Indicates whether this Context is restricted. * * @return {@code true} if this Context is restricted, {@code false} otherwise. diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index e6549187e5c5..a1646a172521 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -1099,6 +1099,11 @@ public class ContextWrapper extends Context { } @Override + public @NonNull Context createDeviceContext(int deviceId) { + return mBase.createDeviceContext(deviceId); + } + + @Override @NonNull public Context createWindowContext(@WindowType int type, @Nullable Bundle options) { return mBase.createWindowContext(type, options); @@ -1167,6 +1172,11 @@ public class ContextWrapper extends Context { } @Override + public int getDeviceId() { + return mBase.getDeviceId(); + } + + @Override public Context createDeviceProtectedStorageContext() { return mBase.createDeviceProtectedStorageContext(); } diff --git a/core/tests/coretests/src/android/content/ContextTest.java b/core/tests/coretests/src/android/content/ContextTest.java index e4a9ce59911b..bc356f80dca1 100644 --- a/core/tests/coretests/src/android/content/ContextTest.java +++ b/core/tests/coretests/src/android/content/ContextTest.java @@ -16,6 +16,7 @@ package android.content; +import static android.companion.virtual.VirtualDeviceManager.DEFAULT_DEVICE_ID; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; import static android.view.Display.DEFAULT_DISPLAY; @@ -210,6 +211,30 @@ public class ContextTest { assertFalse(context.isUiContext()); } + @Test + public void testDeviceIdForSystemContext() { + final Context systemContext = + ActivityThread.currentActivityThread().getSystemContext(); + + assertEquals(systemContext.getDeviceId(), DEFAULT_DEVICE_ID); + } + + @Test + public void testDeviceIdForSystemUiContext() { + final Context systemUiContext = + ActivityThread.currentActivityThread().getSystemUiContext(); + + assertEquals(systemUiContext.getDeviceId(), DEFAULT_DEVICE_ID); + } + + @Test + public void testDeviceIdForTestContext() { + final Context testContext = + InstrumentationRegistry.getInstrumentation().getTargetContext(); + + assertEquals(testContext.getDeviceId(), DEFAULT_DEVICE_ID); + } + private Context createUiContext() { final Context appContext = ApplicationProvider.getApplicationContext(); final DisplayManager displayManager = appContext.getSystemService(DisplayManager.class); diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java index 49daad324bd1..8fc8c7d162f4 100644 --- a/test-mock/src/android/test/mock/MockContext.java +++ b/test-mock/src/android/test/mock/MockContext.java @@ -839,6 +839,11 @@ public class MockContext extends Context { } @Override + public @NonNull Context createDeviceContext(int deviceId) { + throw new UnsupportedOperationException(); + } + + @Override public @NonNull Context createWindowContext(int type, Bundle options) { throw new UnsupportedOperationException(); } @@ -883,6 +888,11 @@ public class MockContext extends Context { } @Override + public int getDeviceId() { + throw new UnsupportedOperationException(); + } + + @Override public File[] getExternalFilesDirs(String type) { throw new UnsupportedOperationException(); } |