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
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
@@ -2946,6 +2973,11 @@ class ContextImpl extends Context {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDeviceId() {
|
||||
return mDeviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DisplayAdjustments getDisplayAdjustments(int displayId) {
|
||||
return mResources.getDisplayAdjustments();
|
||||
|
||||
@@ -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;
|
||||
@@ -6828,6 +6829,30 @@ public abstract class Context {
|
||||
@DisplayContext
|
||||
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.
|
||||
*
|
||||
@@ -7150,6 +7175,20 @@ public abstract class Context {
|
||||
@SuppressWarnings("HiddenAbstractMethod")
|
||||
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.
|
||||
*
|
||||
|
||||
@@ -1098,6 +1098,11 @@ public class ContextWrapper extends Context {
|
||||
return mBase.createDisplayContext(display);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Context createDeviceContext(int deviceId) {
|
||||
return mBase.createDeviceContext(deviceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Context createWindowContext(@WindowType int type, @Nullable Bundle options) {
|
||||
@@ -1166,6 +1171,11 @@ public class ContextWrapper extends Context {
|
||||
mBase.updateDisplay(displayId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDeviceId() {
|
||||
return mBase.getDeviceId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context createDeviceProtectedStorageContext() {
|
||||
return mBase.createDeviceProtectedStorageContext();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -838,6 +838,11 @@ public class MockContext extends Context {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Context createDeviceContext(int deviceId) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Context createWindowContext(int type, Bundle options) {
|
||||
throw new UnsupportedOperationException();
|
||||
@@ -882,6 +887,11 @@ public class MockContext extends Context {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDeviceId() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File[] getExternalFilesDirs(String type) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
Reference in New Issue
Block a user