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.annotation.Nullable;
import android.app.Activity; import android.app.Activity;
import android.app.Application;
import android.content.Context; import android.content.Context;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.window.common.CommonFoldingFeature; import androidx.window.common.CommonFoldingFeature;
import androidx.window.common.DeviceStateManagerFoldingFeatureProducer; import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
import androidx.window.common.EmptyLifecycleCallbacksAdapter;
import androidx.window.common.SettingsDisplayFeatureProducer; import androidx.window.common.SettingsDisplayFeatureProducer;
import androidx.window.util.DataProducer; import androidx.window.util.DataProducer;
import androidx.window.util.PriorityDataProducer; import androidx.window.util.PriorityDataProducer;
@@ -62,6 +66,8 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
private final DataProducer<List<CommonFoldingFeature>> mFoldingFeatureProducer; private final DataProducer<List<CommonFoldingFeature>> mFoldingFeatureProducer;
public WindowLayoutComponentImpl(Context context) { public WindowLayoutComponentImpl(Context context) {
((Application) context.getApplicationContext())
.registerActivityLifecycleCallbacks(new NotifyOnConfigurationChanged());
mSettingsDisplayFeatureProducer = new SettingsDisplayFeatureProducer(context); mSettingsDisplayFeatureProducer = new SettingsDisplayFeatureProducer(context);
mFoldingFeatureProducer = new PriorityDataProducer<>(List.of( mFoldingFeatureProducer = new PriorityDataProducer<>(List.of(
mSettingsDisplayFeatureProducer, mSettingsDisplayFeatureProducer,
@@ -72,6 +78,7 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
/** /**
* Adds a listener interested in receiving updates to {@link WindowLayoutInfo} * Adds a listener interested in receiving updates to {@link WindowLayoutInfo}
*
* @param activity hosting a {@link android.view.Window} * @param activity hosting a {@link android.view.Window}
* @param consumer interested in receiving updates to {@link WindowLayoutInfo} * @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. * Removes a listener no longer interested in receiving updates.
*
* @param consumer no longer interested in receiving updates to {@link WindowLayoutInfo} * @param consumer no longer interested in receiving updates to {@link WindowLayoutInfo}
*/ */
public void removeWindowLayoutInfoListener( public void removeWindowLayoutInfoListener(
@@ -104,6 +112,16 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
return mWindowLayoutChangeListeners.keySet(); 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() { protected boolean hasListeners() {
return !mWindowLayoutChangeListeners.isEmpty(); return !mWindowLayoutChangeListeners.isEmpty();
} }
@@ -115,9 +133,9 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
* possible to translate, then we will return a {@code null} value. * possible to translate, then we will return a {@code null} value.
* *
* @param state if it matches a value in {@link CommonFoldingFeature.State}, {@code null} * @param state if it matches a value in {@link CommonFoldingFeature.State}, {@code null}
* otherwise. @return a {@link FoldingFeature.STATE_FLAT} or * otherwise. @return a {@link FoldingFeature.STATE_FLAT} or
* {@link FoldingFeature.STATE_HALF_OPENED} if the given state matches a value in * {@link FoldingFeature.STATE_HALF_OPENED} if the given state matches a value in
* {@link CommonFoldingFeature.State} and {@code null} otherwise. * {@link CommonFoldingFeature.State} and {@code null} otherwise.
*/ */
@Nullable @Nullable
private Integer convertToExtensionState(int state) { private Integer convertToExtensionState(int state) {
@@ -198,7 +216,27 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
} else { } else {
mSettingsDisplayFeatureProducer.unregisterObserversIfNeeded(); mSettingsDisplayFeatureProducer.unregisterObserversIfNeeded();
} }
onDisplayFeaturesChanged(); 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.Activity;
import android.app.ActivityThread; import android.app.ActivityThread;
import android.app.Application;
import android.content.Context; import android.content.Context;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.window.common.CommonFoldingFeature; import androidx.window.common.CommonFoldingFeature;
import androidx.window.common.DeviceStateManagerFoldingFeatureProducer; import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
import androidx.window.common.EmptyLifecycleCallbacksAdapter;
import androidx.window.common.SettingsDisplayFeatureProducer; import androidx.window.common.SettingsDisplayFeatureProducer;
import androidx.window.util.DataProducer; import androidx.window.util.DataProducer;
import androidx.window.util.PriorityDataProducer; import androidx.window.util.PriorityDataProducer;
@@ -52,6 +55,8 @@ class SampleSidecarImpl extends StubSidecar {
private final SettingsDisplayFeatureProducer mSettingsFoldingFeatureProducer; private final SettingsDisplayFeatureProducer mSettingsFoldingFeatureProducer;
SampleSidecarImpl(Context context) { SampleSidecarImpl(Context context) {
((Application) context.getApplicationContext())
.registerActivityLifecycleCallbacks(new NotifyOnConfigurationChanged());
mSettingsFoldingFeatureProducer = new SettingsDisplayFeatureProducer(context); mSettingsFoldingFeatureProducer = new SettingsDisplayFeatureProducer(context);
mFoldingFeatureProducer = new PriorityDataProducer<>(List.of( mFoldingFeatureProducer = new PriorityDataProducer<>(List.of(
mSettingsFoldingFeatureProducer, mSettingsFoldingFeatureProducer,
@@ -138,8 +143,30 @@ class SampleSidecarImpl extends StubSidecar {
protected void onListenersChanged() { protected void onListenersChanged() {
if (hasListeners()) { if (hasListeners()) {
mSettingsFoldingFeatureProducer.registerObserversIfNeeded(); mSettingsFoldingFeatureProducer.registerObserversIfNeeded();
onDisplayFeaturesChanged();
} else { } else {
mSettingsFoldingFeatureProducer.unregisterObserversIfNeeded(); 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 { abstract class StubSidecar implements SidecarInterface {
private SidecarCallback mSidecarCallback; private SidecarCallback mSidecarCallback;
private final Set<IBinder> mWindowLayoutChangeListenerTokens = new HashSet<>(); final Set<IBinder> mWindowLayoutChangeListenerTokens = new HashSet<>();
private boolean mDeviceStateChangeListenerRegistered; private boolean mDeviceStateChangeListenerRegistered;
StubSidecar() { StubSidecar() {