[automerge] DO NOT MERGE Merge state producer and feature producer. 2p: e5c6ad5d79
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16376128 Bug: 205342008 Change-Id: I512f40adf1c439298fdcd2d7a313a9cdc2b48e18
This commit is contained in:
@@ -18,17 +18,73 @@ package androidx.window.common;
|
|||||||
|
|
||||||
import static androidx.window.util.ExtensionHelper.isZero;
|
import static androidx.window.util.ExtensionHelper.isZero;
|
||||||
|
|
||||||
|
import android.annotation.IntDef;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/** Wrapper for both Extension and Sidecar versions of DisplayFeature. */
|
/** A representation of a folding feature for both Extension and Sidecar.
|
||||||
final class CommonDisplayFeature implements DisplayFeature {
|
* For Sidecar this is the same as combining {@link androidx.window.sidecar.SidecarDeviceState} and
|
||||||
|
* {@link androidx.window.sidecar.SidecarDisplayFeature}. For Extensions this is the mirror of
|
||||||
|
* {@link androidx.window.extensions.layout.FoldingFeature}.
|
||||||
|
*/
|
||||||
|
public final class CommonFoldingFeature {
|
||||||
|
|
||||||
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
|
public static final String TAG = CommonFoldingFeature.class.getSimpleName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A common type to represent a hinge where the screen is continuous.
|
||||||
|
*/
|
||||||
|
public static final int COMMON_TYPE_FOLD = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A common type to represent a hinge where there is a physical gap separating multiple
|
||||||
|
* displays.
|
||||||
|
*/
|
||||||
|
public static final int COMMON_TYPE_HINGE = 2;
|
||||||
|
|
||||||
|
@IntDef({COMMON_TYPE_FOLD, COMMON_TYPE_HINGE})
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
public @interface Type {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A common state to represent when the state is not known. One example is if the device is
|
||||||
|
* closed. We do not emit this value for developers but is useful for implementation reasons.
|
||||||
|
*/
|
||||||
|
public static final int COMMON_STATE_UNKNOWN = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A common state to represent a FLAT hinge. This is needed because the definitions in Sidecar
|
||||||
|
* and Extensions do not match exactly.
|
||||||
|
*/
|
||||||
|
public static final int COMMON_STATE_FLAT = 3;
|
||||||
|
/**
|
||||||
|
* A common state to represent a HALF_OPENED hinge. This is needed because the definitions in
|
||||||
|
* Sidecar and Extensions do not match exactly.
|
||||||
|
*/
|
||||||
|
public static final int COMMON_STATE_HALF_OPENED = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The possible states for a folding hinge.
|
||||||
|
*/
|
||||||
|
@IntDef({COMMON_STATE_FLAT, COMMON_STATE_HALF_OPENED})
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
public @interface State {
|
||||||
|
}
|
||||||
|
|
||||||
private static final Pattern FEATURE_PATTERN =
|
private static final Pattern FEATURE_PATTERN =
|
||||||
Pattern.compile("([a-z]+)-\\[(\\d+),(\\d+),(\\d+),(\\d+)]-?(flat|half-opened)?");
|
Pattern.compile("([a-z]+)-\\[(\\d+),(\\d+),(\\d+),(\\d+)]-?(flat|half-opened)?");
|
||||||
|
|
||||||
@@ -38,17 +94,49 @@ final class CommonDisplayFeature implements DisplayFeature {
|
|||||||
private static final String PATTERN_STATE_FLAT = "flat";
|
private static final String PATTERN_STATE_FLAT = "flat";
|
||||||
private static final String PATTERN_STATE_HALF_OPENED = "half-opened";
|
private static final String PATTERN_STATE_HALF_OPENED = "half-opened";
|
||||||
|
|
||||||
// TODO(b/183049815): Support feature strings that include the state of the feature.
|
/**
|
||||||
|
* Parse a {@link List} of {@link CommonFoldingFeature} from a {@link String}.
|
||||||
|
* @param value a {@link String} representation of multiple {@link CommonFoldingFeature}
|
||||||
|
* separated by a ":".
|
||||||
|
* @param hingeState a global fallback value for a {@link CommonFoldingFeature} if one is not
|
||||||
|
* specified in the input.
|
||||||
|
* @throws IllegalArgumentException if the provided string is improperly formatted or could not
|
||||||
|
* otherwise be parsed.
|
||||||
|
* @see #FEATURE_PATTERN
|
||||||
|
* @return {@link List} of {@link CommonFoldingFeature}.
|
||||||
|
*/
|
||||||
|
static List<CommonFoldingFeature> parseListFromString(@NonNull String value,
|
||||||
|
@State int hingeState) {
|
||||||
|
List<CommonFoldingFeature> features = new ArrayList<>();
|
||||||
|
String[] featureStrings = value.split(";");
|
||||||
|
for (String featureString : featureStrings) {
|
||||||
|
CommonFoldingFeature feature;
|
||||||
|
try {
|
||||||
|
feature = CommonFoldingFeature.parseFromString(featureString, hingeState);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.w(TAG, "Failed to parse display feature: " + featureString, e);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
features.add(feature);
|
||||||
|
}
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a display feature from a string.
|
* Parses a display feature from a string.
|
||||||
*
|
*
|
||||||
|
* @param string A {@link String} representation of a {@link CommonFoldingFeature}.
|
||||||
|
* @param hingeState A fallback value for the {@link State} if it is not specified in the input.
|
||||||
* @throws IllegalArgumentException if the provided string is improperly formatted or could not
|
* @throws IllegalArgumentException if the provided string is improperly formatted or could not
|
||||||
* otherwise be parsed.
|
* otherwise be parsed.
|
||||||
|
* @return {@link CommonFoldingFeature} represented by the {@link String} value.
|
||||||
* @see #FEATURE_PATTERN
|
* @see #FEATURE_PATTERN
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
static CommonDisplayFeature parseFromString(@NonNull String string) {
|
private static CommonFoldingFeature parseFromString(@NonNull String string,
|
||||||
|
@State int hingeState) {
|
||||||
Matcher featureMatcher = FEATURE_PATTERN.matcher(string);
|
Matcher featureMatcher = FEATURE_PATTERN.matcher(string);
|
||||||
if (!featureMatcher.matches()) {
|
if (!featureMatcher.matches()) {
|
||||||
throw new IllegalArgumentException("Malformed feature description format: " + string);
|
throw new IllegalArgumentException("Malformed feature description format: " + string);
|
||||||
@@ -59,10 +147,10 @@ final class CommonDisplayFeature implements DisplayFeature {
|
|||||||
int type;
|
int type;
|
||||||
switch (featureType) {
|
switch (featureType) {
|
||||||
case FEATURE_TYPE_FOLD:
|
case FEATURE_TYPE_FOLD:
|
||||||
type = 1 /* TYPE_FOLD */;
|
type = COMMON_TYPE_FOLD;
|
||||||
break;
|
break;
|
||||||
case FEATURE_TYPE_HINGE:
|
case FEATURE_TYPE_HINGE:
|
||||||
type = 2 /* TYPE_HINGE */;
|
type = COMMON_TYPE_HINGE;
|
||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
throw new IllegalArgumentException("Malformed feature type: " + featureType);
|
throw new IllegalArgumentException("Malformed feature type: " + featureType);
|
||||||
@@ -79,7 +167,7 @@ final class CommonDisplayFeature implements DisplayFeature {
|
|||||||
}
|
}
|
||||||
String stateString = featureMatcher.group(6);
|
String stateString = featureMatcher.group(6);
|
||||||
stateString = stateString == null ? "" : stateString;
|
stateString = stateString == null ? "" : stateString;
|
||||||
Integer state;
|
final int state;
|
||||||
switch (stateString) {
|
switch (stateString) {
|
||||||
case PATTERN_STATE_FLAT:
|
case PATTERN_STATE_FLAT:
|
||||||
state = COMMON_STATE_FLAT;
|
state = COMMON_STATE_FLAT;
|
||||||
@@ -88,10 +176,10 @@ final class CommonDisplayFeature implements DisplayFeature {
|
|||||||
state = COMMON_STATE_HALF_OPENED;
|
state = COMMON_STATE_HALF_OPENED;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
state = null;
|
state = hingeState;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return new CommonDisplayFeature(type, state, featureRect);
|
return new CommonFoldingFeature(type, state, featureRect);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
throw new IllegalArgumentException("Malformed feature description: " + string, e);
|
throw new IllegalArgumentException("Malformed feature description: " + string, e);
|
||||||
}
|
}
|
||||||
@@ -99,11 +187,11 @@ final class CommonDisplayFeature implements DisplayFeature {
|
|||||||
|
|
||||||
private final int mType;
|
private final int mType;
|
||||||
@Nullable
|
@Nullable
|
||||||
private final Integer mState;
|
private final int mState;
|
||||||
@NonNull
|
@NonNull
|
||||||
private final Rect mRect;
|
private final Rect mRect;
|
||||||
|
|
||||||
CommonDisplayFeature(int type, @Nullable Integer state, @NonNull Rect rect) {
|
CommonFoldingFeature(int type, int state, @NonNull Rect rect) {
|
||||||
assertValidState(state);
|
assertValidState(state);
|
||||||
this.mType = type;
|
this.mType = type;
|
||||||
this.mState = state;
|
this.mState = state;
|
||||||
@@ -114,16 +202,19 @@ final class CommonDisplayFeature implements DisplayFeature {
|
|||||||
this.mRect = rect;
|
this.mRect = rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the type of the feature. */
|
||||||
|
@Type
|
||||||
public int getType() {
|
public int getType() {
|
||||||
return mType;
|
return mType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the state of the feature, or {@code null} if the feature has no state. */
|
/** Returns the state of the feature, or {@code null} if the feature has no state. */
|
||||||
@Nullable
|
@State
|
||||||
public Integer getState() {
|
public int getState() {
|
||||||
return mState;
|
return mState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the bounds of the feature. */
|
||||||
@NonNull
|
@NonNull
|
||||||
public Rect getRect() {
|
public Rect getRect() {
|
||||||
return mRect;
|
return mRect;
|
||||||
@@ -133,7 +224,7 @@ final class CommonDisplayFeature implements DisplayFeature {
|
|||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
CommonDisplayFeature that = (CommonDisplayFeature) o;
|
CommonFoldingFeature that = (CommonFoldingFeature) o;
|
||||||
return mType == that.mType
|
return mType == that.mType
|
||||||
&& Objects.equals(mState, that.mState)
|
&& Objects.equals(mState, that.mState)
|
||||||
&& mRect.equals(that.mRect);
|
&& mRect.equals(that.mRect);
|
||||||
@@ -18,11 +18,15 @@ package androidx.window.common;
|
|||||||
|
|
||||||
import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
|
import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
|
||||||
|
|
||||||
|
import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_UNKNOWN;
|
||||||
|
import static androidx.window.common.CommonFoldingFeature.parseListFromString;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.hardware.devicestate.DeviceStateManager;
|
import android.hardware.devicestate.DeviceStateManager;
|
||||||
import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
|
import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
|
|
||||||
@@ -30,6 +34,7 @@ import androidx.window.util.BaseDataProducer;
|
|||||||
|
|
||||||
import com.android.internal.R;
|
import com.android.internal.R;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -37,10 +42,13 @@ import java.util.Optional;
|
|||||||
* by mapping the state returned from {@link DeviceStateManager} to values provided in the resources
|
* by mapping the state returned from {@link DeviceStateManager} to values provided in the resources
|
||||||
* config at {@link R.array#config_device_state_postures}.
|
* config at {@link R.array#config_device_state_postures}.
|
||||||
*/
|
*/
|
||||||
public final class DeviceStateManagerPostureProducer extends BaseDataProducer<Integer> {
|
public final class DeviceStateManagerFoldingFeatureProducer extends
|
||||||
private static final String TAG = "ConfigDevicePostureProducer";
|
BaseDataProducer<List<CommonFoldingFeature>> {
|
||||||
|
private static final String TAG =
|
||||||
|
DeviceStateManagerFoldingFeatureProducer.class.getSimpleName();
|
||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
private final SparseIntArray mDeviceStateToPostureMap = new SparseIntArray();
|
private final SparseIntArray mDeviceStateToPostureMap = new SparseIntArray();
|
||||||
|
|
||||||
private int mCurrentDeviceState = INVALID_DEVICE_STATE;
|
private int mCurrentDeviceState = INVALID_DEVICE_STATE;
|
||||||
@@ -50,7 +58,8 @@ public final class DeviceStateManagerPostureProducer extends BaseDataProducer<In
|
|||||||
notifyDataChanged();
|
notifyDataChanged();
|
||||||
};
|
};
|
||||||
|
|
||||||
public DeviceStateManagerPostureProducer(@NonNull Context context) {
|
public DeviceStateManagerFoldingFeatureProducer(@NonNull Context context) {
|
||||||
|
mContext = context;
|
||||||
String[] deviceStatePosturePairs = context.getResources()
|
String[] deviceStatePosturePairs = context.getResources()
|
||||||
.getStringArray(R.array.config_device_state_postures);
|
.getStringArray(R.array.config_device_state_postures);
|
||||||
for (String deviceStatePosturePair : deviceStatePosturePairs) {
|
for (String deviceStatePosturePair : deviceStatePosturePairs) {
|
||||||
@@ -86,8 +95,17 @@ public final class DeviceStateManagerPostureProducer extends BaseDataProducer<In
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public Optional<Integer> getData() {
|
public Optional<List<CommonFoldingFeature>> getData() {
|
||||||
final int posture = mDeviceStateToPostureMap.get(mCurrentDeviceState, -1);
|
final int globalHingeState = globalHingeState();
|
||||||
return posture != -1 ? Optional.of(posture) : Optional.empty();
|
String displayFeaturesString = mContext.getResources().getString(
|
||||||
|
R.string.config_display_features);
|
||||||
|
if (TextUtils.isEmpty(displayFeaturesString)) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
return Optional.of(parseListFromString(displayFeaturesString, globalHingeState));
|
||||||
|
}
|
||||||
|
|
||||||
|
private int globalHingeState() {
|
||||||
|
return mDeviceStateToPostureMap.get(mCurrentDeviceState, COMMON_STATE_UNKNOWN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2021 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package androidx.window.common;
|
|
||||||
|
|
||||||
import android.annotation.IntDef;
|
|
||||||
import android.annotation.Nullable;
|
|
||||||
import android.graphics.Rect;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
|
|
||||||
/** Wrapper for both Extension and Sidecar versions of DisplayFeature. */
|
|
||||||
public interface DisplayFeature {
|
|
||||||
/** Returns the type of the feature. */
|
|
||||||
int getType();
|
|
||||||
|
|
||||||
/** Returns the state of the feature, or {@code null} if the feature has no state. */
|
|
||||||
@Nullable
|
|
||||||
@State
|
|
||||||
Integer getState();
|
|
||||||
|
|
||||||
/** Returns the bounds of the feature. */
|
|
||||||
@NonNull
|
|
||||||
Rect getRect();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A common state to represent a FLAT hinge. This is needed because the definitions in Sidecar
|
|
||||||
* and Extensions do not match exactly.
|
|
||||||
*/
|
|
||||||
int COMMON_STATE_FLAT = 3;
|
|
||||||
/**
|
|
||||||
* A common state to represent a HALF_OPENED hinge. This is needed because the definitions in
|
|
||||||
* Sidecar and Extensions do not match exactly.
|
|
||||||
*/
|
|
||||||
int COMMON_STATE_HALF_OPENED = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The possible states for a folding hinge.
|
|
||||||
*/
|
|
||||||
@IntDef({COMMON_STATE_FLAT, COMMON_STATE_HALF_OPENED})
|
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
|
||||||
@interface State {}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2021 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package androidx.window.common;
|
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
|
||||||
import android.annotation.Nullable;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.window.util.BaseDataProducer;
|
|
||||||
|
|
||||||
import com.android.internal.R;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of {@link androidx.window.util.DataProducer} that produces
|
|
||||||
* {@link CommonDisplayFeature} parsed from a string stored in the resources config at
|
|
||||||
* {@link R.string#config_display_features}.
|
|
||||||
*/
|
|
||||||
public final class ResourceConfigDisplayFeatureProducer extends
|
|
||||||
BaseDataProducer<List<DisplayFeature>> {
|
|
||||||
private static final boolean DEBUG = false;
|
|
||||||
private static final String TAG = "ResourceConfigDisplayFeatureProducer";
|
|
||||||
|
|
||||||
private final Context mContext;
|
|
||||||
|
|
||||||
public ResourceConfigDisplayFeatureProducer(@NonNull Context context) {
|
|
||||||
mContext = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public Optional<List<DisplayFeature>> getData() {
|
|
||||||
String displayFeaturesString = mContext.getResources().getString(
|
|
||||||
R.string.config_display_features);
|
|
||||||
if (TextUtils.isEmpty(displayFeaturesString)) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<DisplayFeature> features = new ArrayList<>();
|
|
||||||
String[] featureStrings = displayFeaturesString.split(";");
|
|
||||||
for (String featureString : featureStrings) {
|
|
||||||
CommonDisplayFeature feature;
|
|
||||||
try {
|
|
||||||
feature = CommonDisplayFeature.parseFromString(featureString);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.w(TAG, "Failed to parse display feature: " + featureString, e);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
features.add(feature);
|
|
||||||
}
|
|
||||||
return Optional.of(features);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2021 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package androidx.window.common;
|
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
|
||||||
import android.annotation.Nullable;
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.ContentObserver;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.provider.Settings;
|
|
||||||
|
|
||||||
import androidx.window.util.BaseDataProducer;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of {@link androidx.window.util.DataProducer} that provides the device posture
|
|
||||||
* as an {@link Integer} from a value stored in {@link Settings}.
|
|
||||||
*/
|
|
||||||
public final class SettingsDevicePostureProducer extends BaseDataProducer<Integer> {
|
|
||||||
private static final String DEVICE_POSTURE = "device_posture";
|
|
||||||
|
|
||||||
private final Uri mDevicePostureUri =
|
|
||||||
Settings.Global.getUriFor(DEVICE_POSTURE);
|
|
||||||
|
|
||||||
private final ContentResolver mResolver;
|
|
||||||
private final ContentObserver mObserver;
|
|
||||||
private boolean mRegisteredObservers;
|
|
||||||
|
|
||||||
public SettingsDevicePostureProducer(@NonNull Context context) {
|
|
||||||
mResolver = context.getContentResolver();
|
|
||||||
mObserver = new SettingsObserver();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public Optional<Integer> getData() {
|
|
||||||
int posture = Settings.Global.getInt(mResolver, DEVICE_POSTURE, -1);
|
|
||||||
return posture == -1 ? Optional.empty() : Optional.of(posture);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers settings observers, if needed. When settings observers are registered for this
|
|
||||||
* producer callbacks for changes in data will be triggered.
|
|
||||||
*/
|
|
||||||
public void registerObserversIfNeeded() {
|
|
||||||
if (mRegisteredObservers) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mRegisteredObservers = true;
|
|
||||||
mResolver.registerContentObserver(mDevicePostureUri, false /* notifyForDescendants */,
|
|
||||||
mObserver /* ContentObserver */);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unregisters settings observers, if needed. When settings observers are unregistered for this
|
|
||||||
* producer callbacks for changes in data will not be triggered.
|
|
||||||
*/
|
|
||||||
public void unregisterObserversIfNeeded() {
|
|
||||||
if (!mRegisteredObservers) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mRegisteredObservers = false;
|
|
||||||
mResolver.unregisterContentObserver(mObserver);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class SettingsObserver extends ContentObserver {
|
|
||||||
SettingsObserver() {
|
|
||||||
super(new Handler(Looper.getMainLooper()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onChange(boolean selfChange, Uri uri) {
|
|
||||||
if (mDevicePostureUri.equals(uri)) {
|
|
||||||
notifyDataChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,8 +16,10 @@
|
|||||||
|
|
||||||
package androidx.window.common;
|
package androidx.window.common;
|
||||||
|
|
||||||
|
import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_UNKNOWN;
|
||||||
|
import static androidx.window.common.CommonFoldingFeature.parseListFromString;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
@@ -26,22 +28,19 @@ import android.os.Handler;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.window.util.BaseDataProducer;
|
import androidx.window.util.BaseDataProducer;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of {@link androidx.window.util.DataProducer} that produces
|
* Implementation of {@link androidx.window.util.DataProducer} that produces
|
||||||
* {@link CommonDisplayFeature} parsed from a string stored in {@link Settings}.
|
* {@link CommonFoldingFeature} parsed from a string stored in {@link Settings}.
|
||||||
*/
|
*/
|
||||||
public final class SettingsDisplayFeatureProducer
|
public final class SettingsDisplayFeatureProducer
|
||||||
extends BaseDataProducer<List<DisplayFeature>> {
|
extends BaseDataProducer<List<CommonFoldingFeature>> {
|
||||||
private static final boolean DEBUG = false;
|
|
||||||
private static final String TAG = "SettingsDisplayFeatureProducer";
|
|
||||||
private static final String DISPLAY_FEATURES = "display_features";
|
private static final String DISPLAY_FEATURES = "display_features";
|
||||||
|
|
||||||
private final Uri mDisplayFeaturesUri =
|
private final Uri mDisplayFeaturesUri =
|
||||||
@@ -57,32 +56,17 @@ public final class SettingsDisplayFeatureProducer
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@NonNull
|
||||||
public Optional<List<DisplayFeature>> getData() {
|
public Optional<List<CommonFoldingFeature>> getData() {
|
||||||
String displayFeaturesString = Settings.Global.getString(mResolver, DISPLAY_FEATURES);
|
String displayFeaturesString = Settings.Global.getString(mResolver, DISPLAY_FEATURES);
|
||||||
if (displayFeaturesString == null) {
|
if (displayFeaturesString == null) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<DisplayFeature> features = new ArrayList<>();
|
|
||||||
if (TextUtils.isEmpty(displayFeaturesString)) {
|
if (TextUtils.isEmpty(displayFeaturesString)) {
|
||||||
return Optional.of(features);
|
return Optional.of(Collections.emptyList());
|
||||||
}
|
}
|
||||||
String[] featureStrings = displayFeaturesString.split(";");
|
return Optional.of(parseListFromString(displayFeaturesString, COMMON_STATE_UNKNOWN));
|
||||||
|
|
||||||
for (String featureString : featureStrings) {
|
|
||||||
CommonDisplayFeature feature;
|
|
||||||
try {
|
|
||||||
feature = CommonDisplayFeature.parseFromString(featureString);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.w(TAG, "Failed to parse display feature: " + featureString, e);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
features.add(feature);
|
|
||||||
}
|
|
||||||
return Optional.of(features);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ package androidx.window.extensions.layout;
|
|||||||
|
|
||||||
import static android.view.Display.DEFAULT_DISPLAY;
|
import static android.view.Display.DEFAULT_DISPLAY;
|
||||||
|
|
||||||
import static androidx.window.common.DisplayFeature.COMMON_STATE_FLAT;
|
import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_FLAT;
|
||||||
import static androidx.window.common.DisplayFeature.COMMON_STATE_HALF_OPENED;
|
import static androidx.window.common.CommonFoldingFeature.COMMON_STATE_HALF_OPENED;
|
||||||
import static androidx.window.util.ExtensionHelper.rotateRectToDisplayRotation;
|
import static androidx.window.util.ExtensionHelper.rotateRectToDisplayRotation;
|
||||||
import static androidx.window.util.ExtensionHelper.transformToWindowSpaceRect;
|
import static androidx.window.util.ExtensionHelper.transformToWindowSpaceRect;
|
||||||
|
|
||||||
@@ -30,10 +30,8 @@ import android.graphics.Rect;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.window.common.DeviceStateManagerPostureProducer;
|
import androidx.window.common.CommonFoldingFeature;
|
||||||
import androidx.window.common.DisplayFeature;
|
import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
|
||||||
import androidx.window.common.ResourceConfigDisplayFeatureProducer;
|
|
||||||
import androidx.window.common.SettingsDevicePostureProducer;
|
|
||||||
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;
|
||||||
@@ -56,32 +54,20 @@ import java.util.function.Consumer;
|
|||||||
*/
|
*/
|
||||||
public class WindowLayoutComponentImpl implements WindowLayoutComponent {
|
public class WindowLayoutComponentImpl implements WindowLayoutComponent {
|
||||||
private static final String TAG = "SampleExtension";
|
private static final String TAG = "SampleExtension";
|
||||||
private static WindowLayoutComponent sInstance;
|
|
||||||
|
|
||||||
private final Map<Activity, Consumer<WindowLayoutInfo>> mWindowLayoutChangeListeners =
|
private final Map<Activity, Consumer<WindowLayoutInfo>> mWindowLayoutChangeListeners =
|
||||||
new HashMap<>();
|
new HashMap<>();
|
||||||
|
|
||||||
private final SettingsDevicePostureProducer mSettingsDevicePostureProducer;
|
|
||||||
private final DataProducer<Integer> mDevicePostureProducer;
|
|
||||||
|
|
||||||
private final SettingsDisplayFeatureProducer mSettingsDisplayFeatureProducer;
|
private final SettingsDisplayFeatureProducer mSettingsDisplayFeatureProducer;
|
||||||
private final DataProducer<List<DisplayFeature>> mDisplayFeatureProducer;
|
private final DataProducer<List<CommonFoldingFeature>> mFoldingFeatureProducer;
|
||||||
|
|
||||||
public WindowLayoutComponentImpl(Context context) {
|
public WindowLayoutComponentImpl(Context context) {
|
||||||
mSettingsDevicePostureProducer = new SettingsDevicePostureProducer(context);
|
|
||||||
mDevicePostureProducer = new PriorityDataProducer<>(List.of(
|
|
||||||
mSettingsDevicePostureProducer,
|
|
||||||
new DeviceStateManagerPostureProducer(context)
|
|
||||||
));
|
|
||||||
|
|
||||||
mSettingsDisplayFeatureProducer = new SettingsDisplayFeatureProducer(context);
|
mSettingsDisplayFeatureProducer = new SettingsDisplayFeatureProducer(context);
|
||||||
mDisplayFeatureProducer = new PriorityDataProducer<>(List.of(
|
mFoldingFeatureProducer = new PriorityDataProducer<>(List.of(
|
||||||
mSettingsDisplayFeatureProducer,
|
mSettingsDisplayFeatureProducer,
|
||||||
new ResourceConfigDisplayFeatureProducer(context)
|
new DeviceStateManagerFoldingFeatureProducer(context)
|
||||||
));
|
));
|
||||||
|
mFoldingFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
|
||||||
mDevicePostureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
|
|
||||||
mDisplayFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -122,39 +108,20 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
|
|||||||
return !mWindowLayoutChangeListeners.isEmpty();
|
return !mWindowLayoutChangeListeners.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate the {@link DisplayFeature.State} from the feature or the device posture producer.
|
|
||||||
* If the given {@link DisplayFeature.State} is not valid then {@code null} will be returned.
|
|
||||||
* The {@link FoldingFeature} should be ignored in the case of an invalid
|
|
||||||
* {@link DisplayFeature.State}.
|
|
||||||
*
|
|
||||||
* @param feature a {@link DisplayFeature} to provide the feature state if present.
|
|
||||||
* @return {@link DisplayFeature.State} of the hinge if present or the state from the posture
|
|
||||||
* produce if present.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
private Integer getFeatureState(DisplayFeature feature) {
|
|
||||||
Integer featureState = feature.getState();
|
|
||||||
Optional<Integer> posture = mDevicePostureProducer.getData();
|
|
||||||
Integer state = featureState == null ? posture.orElse(null) : featureState;
|
|
||||||
return convertToExtensionState(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A convenience method to translate from the common feature state to the extensions feature
|
* A convenience method to translate from the common feature state to the extensions feature
|
||||||
* state. More specifically, translates from {@link DisplayFeature.State} to
|
* state. More specifically, translates from {@link CommonFoldingFeature.State} to
|
||||||
* {@link FoldingFeature.STATE_FLAT} or {@link FoldingFeature.STATE_HALF_OPENED}. If it is not
|
* {@link FoldingFeature.STATE_FLAT} or {@link FoldingFeature.STATE_HALF_OPENED}. If it is not
|
||||||
* 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 DisplayFeature.State}, {@code null} otherwise.
|
* @param state if it matches a value in {@link CommonFoldingFeature.State}, {@code null}
|
||||||
* @return a {@link FoldingFeature.STATE_FLAT} or {@link FoldingFeature.STATE_HALF_OPENED} if
|
* otherwise. @return a {@link FoldingFeature.STATE_FLAT} or
|
||||||
* the given state matches a value in {@link DisplayFeature.State} and {@code null} otherwise.
|
* {@link FoldingFeature.STATE_HALF_OPENED} if the given state matches a value in
|
||||||
|
* {@link CommonFoldingFeature.State} and {@code null} otherwise.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private Integer convertToExtensionState(@Nullable Integer state) {
|
private Integer convertToExtensionState(int state) {
|
||||||
if (state == null) { // The null check avoids a NullPointerException.
|
if (state == COMMON_STATE_FLAT) {
|
||||||
return null;
|
|
||||||
} else if (state == COMMON_STATE_FLAT) {
|
|
||||||
return FoldingFeature.STATE_FLAT;
|
return FoldingFeature.STATE_FLAT;
|
||||||
} else if (state == COMMON_STATE_HALF_OPENED) {
|
} else if (state == COMMON_STATE_HALF_OPENED) {
|
||||||
return FoldingFeature.STATE_HALF_OPENED;
|
return FoldingFeature.STATE_HALF_OPENED;
|
||||||
@@ -172,33 +139,30 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private WindowLayoutInfo getWindowLayoutInfo(@NonNull Activity activity) {
|
private WindowLayoutInfo getWindowLayoutInfo(@NonNull Activity activity) {
|
||||||
List<androidx.window.extensions.layout.DisplayFeature> displayFeatures =
|
List<DisplayFeature> displayFeatures = getDisplayFeatures(activity);
|
||||||
getDisplayFeatures(activity);
|
|
||||||
return new WindowLayoutInfo(displayFeatures);
|
return new WindowLayoutInfo(displayFeatures);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translate from the {@link DisplayFeature} to
|
* Translate from the {@link CommonFoldingFeature} to
|
||||||
* {@link androidx.window.extensions.layout.DisplayFeature} for a given {@link Activity}. If a
|
* {@link DisplayFeature} for a given {@link Activity}. If a
|
||||||
* {@link DisplayFeature} is not valid then it will be omitted.
|
* {@link CommonFoldingFeature} is not valid then it will be omitted.
|
||||||
*
|
*
|
||||||
* For a {@link FoldingFeature} the bounds are localized into the {@link Activity} window
|
* For a {@link FoldingFeature} the bounds are localized into the {@link Activity} window
|
||||||
* coordinate space and the state is calculated either from {@link DisplayFeature#getState()} or
|
* coordinate space and the state is calculated from {@link CommonFoldingFeature#getState()}.
|
||||||
* {@link #mDisplayFeatureProducer}. The state from {@link #mDisplayFeatureProducer} may not be
|
* The state from {@link #mFoldingFeatureProducer} may not be valid since
|
||||||
* valid since {@link #mDisplayFeatureProducer} is a general state controller. If the state is
|
* {@link #mFoldingFeatureProducer} is a general state controller. If the state is not valid,
|
||||||
* not valid, the {@link FoldingFeature} is omitted from the {@link List} of
|
* the {@link FoldingFeature} is omitted from the {@link List} of {@link DisplayFeature}. If
|
||||||
* {@link androidx.window.extensions.layout.DisplayFeature}. If the bounds are not valid,
|
* the bounds are not valid, constructing a {@link FoldingFeature} will throw an
|
||||||
* constructing a {@link FoldingFeature} will throw an {@link IllegalArgumentException} since
|
* {@link IllegalArgumentException} since this can cause negative UI effects down stream.
|
||||||
* this can cause negative UI effects down stream.
|
|
||||||
*
|
*
|
||||||
* @param activity a proxy for the {@link android.view.Window} that contains the
|
* @param activity a proxy for the {@link android.view.Window} that contains the
|
||||||
* {@link androidx.window.extensions.layout.DisplayFeature}.
|
* {@link DisplayFeature}.
|
||||||
* @return a {@link List} of valid {@link androidx.window.extensions.layout.DisplayFeature} that
|
* @return a {@link List} of valid {@link DisplayFeature} that
|
||||||
* are within the {@link android.view.Window} of the {@link Activity}
|
* are within the {@link android.view.Window} of the {@link Activity}
|
||||||
*/
|
*/
|
||||||
private List<androidx.window.extensions.layout.DisplayFeature> getDisplayFeatures(
|
private List<DisplayFeature> getDisplayFeatures(@NonNull Activity activity) {
|
||||||
@NonNull Activity activity) {
|
List<DisplayFeature> features = new ArrayList<>();
|
||||||
List<androidx.window.extensions.layout.DisplayFeature> features = new ArrayList<>();
|
|
||||||
int displayId = activity.getDisplay().getDisplayId();
|
int displayId = activity.getDisplay().getDisplayId();
|
||||||
if (displayId != DEFAULT_DISPLAY) {
|
if (displayId != DEFAULT_DISPLAY) {
|
||||||
Log.w(TAG, "This sample doesn't support display features on secondary displays");
|
Log.w(TAG, "This sample doesn't support display features on secondary displays");
|
||||||
@@ -211,11 +175,10 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
|
|||||||
return features;
|
return features;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<List<DisplayFeature>> storedFeatures = mDisplayFeatureProducer.getData();
|
Optional<List<CommonFoldingFeature>> storedFeatures = mFoldingFeatureProducer.getData();
|
||||||
if (storedFeatures.isPresent()) {
|
if (storedFeatures.isPresent()) {
|
||||||
|
for (CommonFoldingFeature baseFeature : storedFeatures.get()) {
|
||||||
for (DisplayFeature baseFeature : storedFeatures.get()) {
|
Integer state = convertToExtensionState(baseFeature.getState());
|
||||||
Integer state = getFeatureState(baseFeature);
|
|
||||||
if (state == null) {
|
if (state == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -223,8 +186,7 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
|
|||||||
rotateRectToDisplayRotation(displayId, featureRect);
|
rotateRectToDisplayRotation(displayId, featureRect);
|
||||||
transformToWindowSpaceRect(activity, featureRect);
|
transformToWindowSpaceRect(activity, featureRect);
|
||||||
|
|
||||||
features.add(new FoldingFeature(featureRect, baseFeature.getType(),
|
features.add(new FoldingFeature(featureRect, baseFeature.getType(), state));
|
||||||
getFeatureState(baseFeature)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return features;
|
return features;
|
||||||
@@ -232,10 +194,8 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
|
|||||||
|
|
||||||
private void updateRegistrations() {
|
private void updateRegistrations() {
|
||||||
if (hasListeners()) {
|
if (hasListeners()) {
|
||||||
mSettingsDevicePostureProducer.registerObserversIfNeeded();
|
|
||||||
mSettingsDisplayFeatureProducer.registerObserversIfNeeded();
|
mSettingsDisplayFeatureProducer.registerObserversIfNeeded();
|
||||||
} else {
|
} else {
|
||||||
mSettingsDevicePostureProducer.unregisterObserversIfNeeded();
|
|
||||||
mSettingsDisplayFeatureProducer.unregisterObserversIfNeeded();
|
mSettingsDisplayFeatureProducer.unregisterObserversIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,10 +29,8 @@ import android.os.IBinder;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.window.common.DeviceStateManagerPostureProducer;
|
import androidx.window.common.CommonFoldingFeature;
|
||||||
import androidx.window.common.DisplayFeature;
|
import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
|
||||||
import androidx.window.common.ResourceConfigDisplayFeatureProducer;
|
|
||||||
import androidx.window.common.SettingsDevicePostureProducer;
|
|
||||||
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;
|
||||||
@@ -48,36 +46,23 @@ import java.util.Optional;
|
|||||||
*/
|
*/
|
||||||
class SampleSidecarImpl extends StubSidecar {
|
class SampleSidecarImpl extends StubSidecar {
|
||||||
private static final String TAG = "SampleSidecar";
|
private static final String TAG = "SampleSidecar";
|
||||||
private static final boolean DEBUG = false;
|
|
||||||
|
|
||||||
private final SettingsDevicePostureProducer mSettingsDevicePostureProducer;
|
private final DataProducer<List<CommonFoldingFeature>> mFoldingFeatureProducer;
|
||||||
private final DataProducer<Integer> mDevicePostureProducer;
|
|
||||||
|
|
||||||
private final SettingsDisplayFeatureProducer mSettingsDisplayFeatureProducer;
|
private final SettingsDisplayFeatureProducer mSettingsFoldingFeatureProducer;
|
||||||
private final DataProducer<List<DisplayFeature>> mDisplayFeatureProducer;
|
|
||||||
|
|
||||||
SampleSidecarImpl(Context context) {
|
SampleSidecarImpl(Context context) {
|
||||||
mSettingsDevicePostureProducer = new SettingsDevicePostureProducer(context);
|
mSettingsFoldingFeatureProducer = new SettingsDisplayFeatureProducer(context);
|
||||||
mDevicePostureProducer = new PriorityDataProducer<>(List.of(
|
mFoldingFeatureProducer = new PriorityDataProducer<>(List.of(
|
||||||
mSettingsDevicePostureProducer,
|
mSettingsFoldingFeatureProducer,
|
||||||
new DeviceStateManagerPostureProducer(context)
|
new DeviceStateManagerFoldingFeatureProducer(context)
|
||||||
));
|
));
|
||||||
|
|
||||||
mSettingsDisplayFeatureProducer = new SettingsDisplayFeatureProducer(context);
|
mFoldingFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
|
||||||
mDisplayFeatureProducer = new PriorityDataProducer<>(List.of(
|
|
||||||
mSettingsDisplayFeatureProducer,
|
|
||||||
new ResourceConfigDisplayFeatureProducer(context)
|
|
||||||
));
|
|
||||||
|
|
||||||
mDevicePostureProducer.addDataChangedCallback(this::onDevicePostureChanged);
|
|
||||||
mDisplayFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onDevicePostureChanged() {
|
|
||||||
updateDeviceState(getDeviceState());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDisplayFeaturesChanged() {
|
private void onDisplayFeaturesChanged() {
|
||||||
|
updateDeviceState(getDeviceState());
|
||||||
for (IBinder windowToken : getWindowsListeningForLayoutChanges()) {
|
for (IBinder windowToken : getWindowsListeningForLayoutChanges()) {
|
||||||
SidecarWindowLayoutInfo newLayout = getWindowLayoutInfo(windowToken);
|
SidecarWindowLayoutInfo newLayout = getWindowLayoutInfo(windowToken);
|
||||||
updateWindowLayout(windowToken, newLayout);
|
updateWindowLayout(windowToken, newLayout);
|
||||||
@@ -87,27 +72,21 @@ class SampleSidecarImpl extends StubSidecar {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public SidecarDeviceState getDeviceState() {
|
public SidecarDeviceState getDeviceState() {
|
||||||
Optional<Integer> posture = mDevicePostureProducer.getData();
|
|
||||||
|
|
||||||
SidecarDeviceState deviceState = new SidecarDeviceState();
|
SidecarDeviceState deviceState = new SidecarDeviceState();
|
||||||
deviceState.posture = posture.orElse(deviceStateFromFeature());
|
deviceState.posture = deviceStateFromFeature();
|
||||||
return deviceState;
|
return deviceState;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int deviceStateFromFeature() {
|
private int deviceStateFromFeature() {
|
||||||
List<DisplayFeature> storedFeatures = mDisplayFeatureProducer.getData()
|
List<CommonFoldingFeature> storedFeatures = mFoldingFeatureProducer.getData()
|
||||||
.orElse(Collections.emptyList());
|
.orElse(Collections.emptyList());
|
||||||
for (int i = 0; i < storedFeatures.size(); i++) {
|
for (int i = 0; i < storedFeatures.size(); i++) {
|
||||||
DisplayFeature feature = storedFeatures.get(i);
|
CommonFoldingFeature feature = storedFeatures.get(i);
|
||||||
final int state = feature.getState() == null ? -1 : feature.getState();
|
final int state = feature.getState();
|
||||||
if (DEBUG && feature.getState() == null) {
|
|
||||||
Log.d(TAG, "feature#getState was null for DisplayFeature: " + feature);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case DisplayFeature.COMMON_STATE_FLAT:
|
case CommonFoldingFeature.COMMON_STATE_FLAT:
|
||||||
return SidecarDeviceState.POSTURE_OPENED;
|
return SidecarDeviceState.POSTURE_OPENED;
|
||||||
case DisplayFeature.COMMON_STATE_HALF_OPENED:
|
case CommonFoldingFeature.COMMON_STATE_HALF_OPENED:
|
||||||
return SidecarDeviceState.POSTURE_HALF_OPENED;
|
return SidecarDeviceState.POSTURE_HALF_OPENED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,22 +106,22 @@ class SampleSidecarImpl extends StubSidecar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<SidecarDisplayFeature> getDisplayFeatures(@NonNull Activity activity) {
|
private List<SidecarDisplayFeature> getDisplayFeatures(@NonNull Activity activity) {
|
||||||
List<SidecarDisplayFeature> features = new ArrayList<SidecarDisplayFeature>();
|
|
||||||
int displayId = activity.getDisplay().getDisplayId();
|
int displayId = activity.getDisplay().getDisplayId();
|
||||||
if (displayId != DEFAULT_DISPLAY) {
|
if (displayId != DEFAULT_DISPLAY) {
|
||||||
Log.w(TAG, "This sample doesn't support display features on secondary displays");
|
Log.w(TAG, "This sample doesn't support display features on secondary displays");
|
||||||
return features;
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activity.isInMultiWindowMode()) {
|
if (activity.isInMultiWindowMode()) {
|
||||||
// It is recommended not to report any display features in multi-window mode, since it
|
// It is recommended not to report any display features in multi-window mode, since it
|
||||||
// won't be possible to synchronize the display feature positions with window movement.
|
// won't be possible to synchronize the display feature positions with window movement.
|
||||||
return features;
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<List<DisplayFeature>> storedFeatures = mDisplayFeatureProducer.getData();
|
Optional<List<CommonFoldingFeature>> storedFeatures = mFoldingFeatureProducer.getData();
|
||||||
|
List<SidecarDisplayFeature> features = new ArrayList<>();
|
||||||
if (storedFeatures.isPresent()) {
|
if (storedFeatures.isPresent()) {
|
||||||
for (DisplayFeature baseFeature : storedFeatures.get()) {
|
for (CommonFoldingFeature baseFeature : storedFeatures.get()) {
|
||||||
SidecarDisplayFeature feature = new SidecarDisplayFeature();
|
SidecarDisplayFeature feature = new SidecarDisplayFeature();
|
||||||
Rect featureRect = baseFeature.getRect();
|
Rect featureRect = baseFeature.getRect();
|
||||||
rotateRectToDisplayRotation(displayId, featureRect);
|
rotateRectToDisplayRotation(displayId, featureRect);
|
||||||
@@ -152,17 +131,15 @@ class SampleSidecarImpl extends StubSidecar {
|
|||||||
features.add(feature);
|
features.add(feature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return features;
|
return Collections.unmodifiableList(features);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onListenersChanged() {
|
protected void onListenersChanged() {
|
||||||
if (hasListeners()) {
|
if (hasListeners()) {
|
||||||
mSettingsDevicePostureProducer.registerObserversIfNeeded();
|
mSettingsFoldingFeatureProducer.registerObserversIfNeeded();
|
||||||
mSettingsDisplayFeatureProducer.registerObserversIfNeeded();
|
|
||||||
} else {
|
} else {
|
||||||
mSettingsDevicePostureProducer.unregisterObserversIfNeeded();
|
mSettingsFoldingFeatureProducer.unregisterObserversIfNeeded();
|
||||||
mSettingsDisplayFeatureProducer.unregisterObserversIfNeeded();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user