summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vladimir Komsiyski <vladokom@google.com> 2022-10-05 14:09:28 +0200
committer Vladimir Komsiyski <vladokom@google.com> 2022-10-17 17:45:53 +0200
commit7c1be3298d99cde28ac39b3095391065d619eaa8 (patch)
tree781e79b896625a8a8bf93e96c3e5fa3c8948b38d
parent0050a51961000057f7858bb2b8892892aaad3232 (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.txt2
-rw-r--r--core/java/android/app/ContextImpl.java32
-rw-r--r--core/java/android/content/Context.java39
-rw-r--r--core/java/android/content/ContextWrapper.java10
-rw-r--r--core/tests/coretests/src/android/content/ContextTest.java25
-rw-r--r--test-mock/src/android/test/mock/MockContext.java10
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();
}