Add WindowProvider support to WindowLayoutComponentImpl and allow

WindowProviderService to broadcast configuration changes to listeners.

This is needed to allow IME to listen to WindowLayoutInfo changes.

Bug: 237342281
Test: CTS InputMethodServiceTest
Change-Id: Id8ddce5889b52859172caf3b4f0763bb5010b5dc
This commit is contained in:
An An Yu
2022-10-23 07:21:54 +00:00
parent f4369fe1f1
commit 4a999424a3
3 changed files with 70 additions and 12 deletions

View File

@@ -15,8 +15,10 @@
*/
package android.window;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Bundle;
import android.os.IBinder;
import android.view.WindowManager.LayoutParams.WindowType;
/**
@@ -36,4 +38,11 @@ public interface WindowProvider {
/** Gets the launch options of this provider */
@Nullable
Bundle getWindowContextOptions();
/**
* Gets the WindowContextToken of this provider.
* @see android.content.Context#getWindowContextToken
*/
@NonNull
IBinder getWindowContextToken();
}

View File

@@ -27,7 +27,10 @@ import android.annotation.UiContext;
import android.app.ActivityThread;
import android.app.LoadedApk;
import android.app.Service;
import android.content.ComponentCallbacks;
import android.content.ComponentCallbacksController;
import android.content.Context;
import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.os.IBinder;
@@ -54,6 +57,8 @@ public abstract class WindowProviderService extends Service implements WindowPro
private final WindowContextController mController = new WindowContextController(mWindowToken);
private WindowManager mWindowManager;
private boolean mInitialized;
private final ComponentCallbacksController mCallbacksController =
new ComponentCallbacksController();
/**
* Returns {@code true} if the {@code windowContextOptions} declares that it is a
@@ -118,6 +123,48 @@ public abstract class WindowProviderService extends Service implements WindowPro
return mOptions;
}
@SuppressLint({"OnNameExpected", "ExecutorRegistration"})
// Suppress lint because this is a legacy named function and doesn't have an optional param
// for executor.
// TODO(b/259347943): Update documentation for U.
/**
* Here we override to prevent WindowProviderService from invoking
* {@link Application.registerComponentCallback}, which will result in callback registered
* for process-level Configuration change updates.
*/
@Override
public void registerComponentCallbacks(@NonNull ComponentCallbacks callback) {
// For broadcasting Configuration Changes.
mCallbacksController.registerCallbacks(callback);
}
@SuppressLint("OnNameExpected")
@Override
public void unregisterComponentCallbacks(@NonNull ComponentCallbacks callback) {
mCallbacksController.unregisterCallbacks(callback);
}
@SuppressLint("OnNameExpected")
@Override
public void onConfigurationChanged(@Nullable Configuration configuration) {
// This is only called from WindowTokenClient.
mCallbacksController.dispatchConfigurationChanged(configuration);
}
/**
* Override {@link Service}'s empty implementation and listen to {@link ActivityThread} for
* low memory and trim memory events.
*/
@Override
public void onLowMemory() {
mCallbacksController.dispatchLowMemory();
}
@Override
public void onTrimMemory(int level) {
mCallbacksController.dispatchTrimMemory(level);
}
/**
* Returns the display ID to launch this {@link WindowProviderService}.
*
@@ -181,5 +228,6 @@ public abstract class WindowProviderService extends Service implements WindowPro
public void onDestroy() {
super.onDestroy();
mController.detachIfNeeded();
mCallbacksController.clearCallbacks();
}
}

View File

@@ -36,6 +36,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.util.ArrayMap;
import android.window.WindowContext;
import android.window.WindowProvider;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -71,7 +72,7 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
private final List<CommonFoldingFeature> mLastReportedFoldingFeatures = new ArrayList<>();
private final Map<IBinder, WindowContextConfigListener> mWindowContextConfigListeners =
private final Map<IBinder, ConfigurationChangeListener> mConfigurationChangeListeners =
new ArrayMap<>();
public WindowLayoutComponentImpl(@NonNull Context context) {
@@ -121,21 +122,21 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
}
if (!context.isUiContext()) {
throw new IllegalArgumentException("Context must be a UI Context, which should be"
+ " an Activity or a WindowContext");
+ " an Activity, WindowContext or InputMethodService");
}
mFoldingFeatureProducer.getData((features) -> {
// Get the WindowLayoutInfo from the activity and pass the value to the layoutConsumer.
WindowLayoutInfo newWindowLayout = getWindowLayoutInfo(context, features);
consumer.accept(newWindowLayout);
});
mWindowLayoutChangeListeners.put(context, consumer);
if (context instanceof WindowContext) {
// TODO(b/258065175) Further extend this to ContextWrappers.
if (context instanceof WindowProvider) {
final IBinder windowContextToken = context.getWindowContextToken();
final WindowContextConfigListener listener =
new WindowContextConfigListener(windowContextToken);
final ConfigurationChangeListener listener =
new ConfigurationChangeListener(windowContextToken);
context.registerComponentCallbacks(listener);
mWindowContextConfigListeners.put(windowContextToken, listener);
mConfigurationChangeListeners.put(windowContextToken, listener);
}
}
@@ -150,10 +151,10 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
if (!mWindowLayoutChangeListeners.get(context).equals(consumer)) {
continue;
}
if (context instanceof WindowContext) {
if (context instanceof WindowProvider) {
final IBinder token = context.getWindowContextToken();
context.unregisterComponentCallbacks(mWindowContextConfigListeners.get(token));
mWindowContextConfigListeners.remove(token);
context.unregisterComponentCallbacks(mConfigurationChangeListeners.get(token));
mConfigurationChangeListeners.remove(token);
}
break;
}
@@ -349,10 +350,10 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
}
}
private final class WindowContextConfigListener implements ComponentCallbacks {
private final class ConfigurationChangeListener implements ComponentCallbacks {
final IBinder mToken;
WindowContextConfigListener(IBinder token) {
ConfigurationChangeListener(IBinder token) {
mToken = token;
}