Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7c1be329 authored by Vladimir Komsiyski's avatar Vladimir Komsiyski
Browse files

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
parent 0050a519
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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);
+32 −0
Original line number Diff line number Diff line
@@ -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();
+39 −0
Original line number Diff line number Diff line
@@ -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.
     *
+10 −0
Original line number Diff line number Diff line
@@ -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();
+25 −0
Original line number Diff line number Diff line
@@ -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);
Loading