Skip to content

Commit

Permalink
Add a UI Context for RootTaskDisplayAreaOrganizer
Browse files Browse the repository at this point in the history
Bug: 175416931
Test: atest SplitScreenTests WMShellUnitTests

Change-Id: Id11bfef19076840e46222014e268a553bd94f2ef
  • Loading branch information
CharlesCCChen committed Jan 7, 2021
1 parent f749076 commit 74e1d37
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 6 deletions.
14 changes: 14 additions & 0 deletions core/java/android/app/ContextImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -2489,6 +2489,20 @@ public WindowContext createWindowContext(@NonNull Display display, int type,
return new WindowContext(this, display, type, options);
}

@NonNull
@Override
public Context createTokenContext(@NonNull IBinder token, @NonNull Display display) {
if (display == null) {
throw new UnsupportedOperationException("Token context can only be created from "
+ "other visual contexts, such as Activity or one created with "
+ "Context#createDisplayContext(Display)");
}
final ContextImpl tokenContext = createBaseWindowContext(token, display);
tokenContext.setResources(createWindowContextResources());
return tokenContext;
}


ContextImpl createBaseWindowContext(IBinder token, Display display) {
ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag,
mSplitName, token, mUser, mFlags, mClassLoader, null);
Expand Down
26 changes: 22 additions & 4 deletions core/java/android/content/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -6014,10 +6014,13 @@ public Context createWindowContext(@WindowType int type, @Nullable Bundle option
}

/**
* A special version of {@link #createWindowContext(int, Bundle)} which also takes
* {@link Display}. The only difference between this API and
* {@link #createWindowContext(int, Bundle)} is that this API can create window context from
* any context even if the context which is not associated to a {@link Display} instance.
* Creates a {@code Context} for a non-{@link android.app.Activity activity} window on the given
* {@link Display}.
*
* <p>
* Similar to {@link #createWindowContext(int, Bundle)}, but the {@code display} is passed in,
* instead of implicitly using the {@link #getDisplay() original Context's Display}.
* </p>
*
* @param display The {@link Display} to associate with
* @param type Window type in {@link WindowManager.LayoutParams}
Expand Down Expand Up @@ -6122,6 +6125,21 @@ public Context createWindowContext(@NonNull Display display, @WindowType int typ
@SystemApi
public abstract Context createCredentialProtectedStorageContext();

/**
* Creates a UI context with a {@code token}. The users of this API should handle this context's
* configuration changes.
*
* @param token The token to associate with the {@link Resources}
* @param display The display to associate with the token context
*
* @hide
*/
@UiContext
@NonNull
public Context createTokenContext(@NonNull IBinder token, @NonNull Display display) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}

/**
* Gets the display adjustments holder for this context. This information
* is provided on a per-application or activity basis and is used to simulate lower density
Expand Down
9 changes: 9 additions & 0 deletions core/java/android/content/ContextWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UiContext;
import android.app.IApplicationThread;
import android.app.IServiceConnection;
import android.compat.annotation.UnsupportedAppUsage;
Expand Down Expand Up @@ -1049,6 +1050,14 @@ public Context createCredentialProtectedStorageContext() {
return mBase.createCredentialProtectedStorageContext();
}

/** @hide */
@UiContext
@NonNull
@Override
public Context createTokenContext(@NonNull IBinder token, @NonNull Display display) {
return mBase.createTokenContext(token, display);
}

@Override
public boolean isDeviceProtectedStorage() {
return mBase.isDeviceProtectedStorage();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,23 @@

package com.android.wm.shell;

import android.annotation.UiContext;
import android.app.ResourcesManager;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
import android.os.Binder;
import android.os.IBinder;
import android.util.SparseArray;
import android.view.Display;
import android.view.SurfaceControl;
import android.window.DisplayAreaAppearedInfo;
import android.window.DisplayAreaInfo;
import android.window.DisplayAreaOrganizer;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.io.PrintWriter;
import java.util.ArrayList;
Expand All @@ -42,8 +52,13 @@ public class RootTaskDisplayAreaOrganizer extends DisplayAreaOrganizer {
private final SparseArray<ArrayList<RootTaskDisplayAreaListener>> mListeners =
new SparseArray<>();

public RootTaskDisplayAreaOrganizer(Executor executor) {
private final SparseArray<DisplayAreaContext> mDisplayAreaContexts = new SparseArray<>();

private final Context mContext;

public RootTaskDisplayAreaOrganizer(Executor executor, Context context) {
super(executor);
mContext = context;
List<DisplayAreaAppearedInfo> infos = registerOrganizer(FEATURE_DEFAULT_TASK_CONTAINER);
for (int i = infos.size() - 1; i >= 0; --i) {
onDisplayAreaAppeared(infos.get(i).getDisplayAreaInfo(), infos.get(i).getLeash());
Expand Down Expand Up @@ -103,6 +118,7 @@ public void onDisplayAreaAppeared(@NonNull DisplayAreaInfo displayAreaInfo,
listeners.get(i).onDisplayAreaAppeared(displayAreaInfo);
}
}
applyConfigChangesToContext(displayId, displayAreaInfo.configuration);
}

@Override
Expand All @@ -123,6 +139,7 @@ public void onDisplayAreaVanished(@NonNull DisplayAreaInfo displayAreaInfo) {
listeners.get(i).onDisplayAreaVanished(displayAreaInfo);
}
}
mDisplayAreaContexts.remove(displayId);
}

@Override
Expand All @@ -143,6 +160,33 @@ public void onDisplayAreaInfoChanged(@NonNull DisplayAreaInfo displayAreaInfo) {
listeners.get(i).onDisplayAreaInfoChanged(displayAreaInfo);
}
}
applyConfigChangesToContext(displayId, displayAreaInfo.configuration);
}

/**
* Applies the {@link Configuration} to the {@link DisplayAreaContext} specified by
* {@code displayId}.
*
* @param displayId The ID of the {@link Display} which the {@link DisplayAreaContext} is
* associated with
* @param newConfig The propagated configuration
*/
private void applyConfigChangesToContext(int displayId, @NonNull Configuration newConfig) {
DisplayAreaContext daContext = mDisplayAreaContexts.get(displayId);
if (daContext == null) {
daContext = new DisplayAreaContext(mContext, displayId);
mDisplayAreaContexts.put(displayId, daContext);
}
daContext.updateConfigurationChanges(newConfig);
}

/**
* Returns the UI context associated with RootTaskDisplayArea specified by {@code displayId}.
*/
@Nullable
@UiContext
public Context getContext(int displayId) {
return mDisplayAreaContexts.get(displayId);
}

public void dump(@NonNull PrintWriter pw, String prefix) {
Expand Down Expand Up @@ -170,4 +214,32 @@ default void onDisplayAreaInfoChanged(DisplayAreaInfo displayAreaInfo) {
default void dump(@NonNull PrintWriter pw, String prefix) {
}
}

/**
* A UI context to associate with a {@link com.android.server.wm.DisplayArea}.
*
* This context receives configuration changes through {@link DisplayAreaOrganizer} callbacks
* and the core implementation is {@link Context#createTokenContext(IBinder, Display)} to apply
* the configuration updates to the {@link android.content.res.Resources}.
*/
@UiContext
public static class DisplayAreaContext extends ContextWrapper {
private final IBinder mToken = new Binder();
private final ResourcesManager mResourcesManager = ResourcesManager.getInstance();

public DisplayAreaContext(@NonNull Context context, int displayId) {
super(null);
final Display display = context.getSystemService(DisplayManager.class)
.getDisplay(displayId);
attachBaseContext(context.createTokenContext(mToken, display));
}

private void updateConfigurationChanges(@NonNull Configuration newConfig) {
final Configuration config = getResources().getConfiguration();
final boolean configChanged = config.diff(newConfig) != 0;
if (configChanged) {
mResourcesManager.updateResourcesForActivity(mToken, newConfig, getDisplayId());
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ static ShellTaskOrganizer provideShellTaskOrganizer(@ShellMainThread ShellExecut
@Provides
static RootTaskDisplayAreaOrganizer provideRootTaskDisplayAreaOrganizer(
@ShellMainThread ShellExecutor mainExecutor, Context context) {
return new RootTaskDisplayAreaOrganizer(mainExecutor);
return new RootTaskDisplayAreaOrganizer(mainExecutor, context);
}

@WMSingleton
Expand Down
6 changes: 6 additions & 0 deletions test-mock/src/android/test/mock/MockContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -891,6 +891,12 @@ public Context createCredentialProtectedStorageContext() {
throw new UnsupportedOperationException();
}

/** @hide */
@Override
public Context createTokenContext(@NonNull IBinder token, @NonNull Display display) {
throw new UnsupportedOperationException();
}

@Override
public boolean isDeviceProtectedStorage() {
throw new UnsupportedOperationException();
Expand Down

0 comments on commit 74e1d37

Please sign in to comment.