DO NOT MERGE Listen for config changes when updating features.

Listen for configuration changes to push out folding feature changes.
Fixes a bug where the reference implementation would not emit the
correct folding feature if a configuration changed. The effect was that
you would see the folding feature for portait while in landscape or
vice-versa.

Maintains parity with Sidecar providing updates for Activities that do
not handle configuration changes.

Bug: 205342008, 206697963
Test: Manual - Open the sample app and use the application that &&
  handles configuration changes.  &&
  Expect the folding feature to match the physical orientation
Test: Manual - open an app that handles PiP and folding features &&
  Flattend the device and put app into PiP &&
  Fold device and put PiP app in full screen. &&
  Expect the app to react to fold.
Test: atest CtsWindowManagerJetpackTestCases
Change-Id: I726827c9f1482ddd0b55a6839e34660deb340767
This commit is contained in:
Diego Vela
2021-12-02 10:39:05 -08:00
parent 396a7965c3
commit 6c39d4fb3c
3 changed files with 70 additions and 5 deletions

View File

@@ -25,13 +25,17 @@ import static androidx.window.util.ExtensionHelper.transformToWindowSpaceRect;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.window.common.CommonFoldingFeature;
import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
import androidx.window.common.EmptyLifecycleCallbacksAdapter;
import androidx.window.common.SettingsDisplayFeatureProducer;
import androidx.window.util.DataProducer;
import androidx.window.util.PriorityDataProducer;
@@ -62,6 +66,8 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
private final DataProducer<List<CommonFoldingFeature>> mFoldingFeatureProducer;
public WindowLayoutComponentImpl(Context context) {
((Application) context.getApplicationContext())
.registerActivityLifecycleCallbacks(new NotifyOnConfigurationChanged());
mSettingsDisplayFeatureProducer = new SettingsDisplayFeatureProducer(context);
mFoldingFeatureProducer = new PriorityDataProducer<>(List.of(
mSettingsDisplayFeatureProducer,
@@ -72,6 +78,7 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
/**
* Adds a listener interested in receiving updates to {@link WindowLayoutInfo}
*
* @param activity hosting a {@link android.view.Window}
* @param consumer interested in receiving updates to {@link WindowLayoutInfo}
*/
@@ -83,6 +90,7 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
/**
* Removes a listener no longer interested in receiving updates.
*
* @param consumer no longer interested in receiving updates to {@link WindowLayoutInfo}
*/
public void removeWindowLayoutInfoListener(
@@ -104,6 +112,16 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
return mWindowLayoutChangeListeners.keySet();
}
@NonNull
private Boolean isListeningForLayoutChanges(IBinder token) {
for (Activity activity: getActivitiesListeningForLayoutChanges()) {
if (token.equals(activity.getWindow().getAttributes().token)) {
return true;
}
}
return false;
}
protected boolean hasListeners() {
return !mWindowLayoutChangeListeners.isEmpty();
}
@@ -115,9 +133,9 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
* possible to translate, then we will return a {@code null} value.
*
* @param state if it matches a value in {@link CommonFoldingFeature.State}, {@code null}
* otherwise. @return a {@link FoldingFeature.STATE_FLAT} or
* {@link FoldingFeature.STATE_HALF_OPENED} if the given state matches a value in
* {@link CommonFoldingFeature.State} and {@code null} otherwise.
* otherwise. @return a {@link FoldingFeature.STATE_FLAT} or
* {@link FoldingFeature.STATE_HALF_OPENED} if the given state matches a value in
* {@link CommonFoldingFeature.State} and {@code null} otherwise.
*/
@Nullable
private Integer convertToExtensionState(int state) {
@@ -198,7 +216,27 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
} else {
mSettingsDisplayFeatureProducer.unregisterObserversIfNeeded();
}
onDisplayFeaturesChanged();
}
private final class NotifyOnConfigurationChanged extends EmptyLifecycleCallbacksAdapter {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
super.onActivityCreated(activity, savedInstanceState);
onDisplayFeaturesChangedIfListening(activity);
}
@Override
public void onActivityConfigurationChanged(Activity activity) {
super.onActivityConfigurationChanged(activity);
onDisplayFeaturesChangedIfListening(activity);
}
private void onDisplayFeaturesChangedIfListening(Activity activity) {
IBinder token = activity.getWindow().getAttributes().token;
if (token == null || isListeningForLayoutChanges(token)) {
onDisplayFeaturesChanged();
}
}
}
}

View File

@@ -23,14 +23,17 @@ import static androidx.window.util.ExtensionHelper.transformToWindowSpaceRect;
import android.app.Activity;
import android.app.ActivityThread;
import android.app.Application;
import android.content.Context;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.window.common.CommonFoldingFeature;
import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
import androidx.window.common.EmptyLifecycleCallbacksAdapter;
import androidx.window.common.SettingsDisplayFeatureProducer;
import androidx.window.util.DataProducer;
import androidx.window.util.PriorityDataProducer;
@@ -52,6 +55,8 @@ class SampleSidecarImpl extends StubSidecar {
private final SettingsDisplayFeatureProducer mSettingsFoldingFeatureProducer;
SampleSidecarImpl(Context context) {
((Application) context.getApplicationContext())
.registerActivityLifecycleCallbacks(new NotifyOnConfigurationChanged());
mSettingsFoldingFeatureProducer = new SettingsDisplayFeatureProducer(context);
mFoldingFeatureProducer = new PriorityDataProducer<>(List.of(
mSettingsFoldingFeatureProducer,
@@ -138,8 +143,30 @@ class SampleSidecarImpl extends StubSidecar {
protected void onListenersChanged() {
if (hasListeners()) {
mSettingsFoldingFeatureProducer.registerObserversIfNeeded();
onDisplayFeaturesChanged();
} else {
mSettingsFoldingFeatureProducer.unregisterObserversIfNeeded();
}
}
private final class NotifyOnConfigurationChanged extends EmptyLifecycleCallbacksAdapter {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
super.onActivityCreated(activity, savedInstanceState);
onDisplayFeaturesChangedForActivity(activity);
}
@Override
public void onActivityConfigurationChanged(Activity activity) {
super.onActivityConfigurationChanged(activity);
onDisplayFeaturesChangedForActivity(activity);
}
private void onDisplayFeaturesChangedForActivity(@NonNull Activity activity) {
IBinder token = activity.getWindow().getAttributes().token;
if (token == null || mWindowLayoutChangeListenerTokens.contains(token)) {
onDisplayFeaturesChanged();
}
}
}
}

View File

@@ -30,7 +30,7 @@ import java.util.Set;
abstract class StubSidecar implements SidecarInterface {
private SidecarCallback mSidecarCallback;
private final Set<IBinder> mWindowLayoutChangeListenerTokens = new HashSet<>();
final Set<IBinder> mWindowLayoutChangeListenerTokens = new HashSet<>();
private boolean mDeviceStateChangeListenerRegistered;
StubSidecar() {