Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9171859f authored by Darryl L Johnson's avatar Darryl L Johnson
Browse files

Seperate SettingsConfigProvider into producers.

This provides a clear separation between the data producing classes and
the core library class. It also allows seperating the logic in
SettingsConfigProvider into different producers that provide their data
from different sources (for ex, settings vs resources).

Bug: 173428759
Test: Manual - flash device and verify
Test: ./gradlew window:window:test

Change-Id: I111058ff7c3479bc53aede0b29de1e2e1c2ff91f
parent 463ec227
Loading
Loading
Loading
Loading
+20 −6
Original line number Original line Diff line number Diff line
@@ -30,13 +30,20 @@ android_library_import {


java_library {
java_library {
    name: "androidx.window.sidecar",
    name: "androidx.window.sidecar",
    srcs: ["src/androidx/window/sidecar/**/*.java", "src/androidx/window/util/**/*.java"],
    srcs: [
        "src/androidx/window/sidecar/**/*.java",
        "src/androidx/window/util/**/*.java",
        "src/androidx/window/common/**/*.java",
    ],
    static_libs: ["window-sidecar"],
    static_libs: ["window-sidecar"],
    installable: true,
    installable: true,
    sdk_version: "core_platform",
    sdk_version: "core_platform",
    system_ext_specific: true,
    system_ext_specific: true,
    libs: ["framework", "androidx.annotation_annotation",],
    libs: [
    required: ["androidx.window.sidecar.xml",],
        "framework",
        "androidx.annotation_annotation",
    ],
    required: ["androidx.window.sidecar.xml"],
}
}


prebuilt_etc {
prebuilt_etc {
@@ -58,13 +65,20 @@ android_library_import {


java_library {
java_library {
    name: "androidx.window.extensions",
    name: "androidx.window.extensions",
    srcs: ["src/androidx/window/extensions/**/*.java", "src/androidx/window/util/**/*.java"],
    srcs: [
        "src/androidx/window/extensions/**/*.java",
        "src/androidx/window/util/**/*.java",
        "src/androidx/window/common/**/*.java",
    ],
    static_libs: ["window-extensions"],
    static_libs: ["window-extensions"],
    installable: true,
    installable: true,
    sdk_version: "core_platform",
    sdk_version: "core_platform",
    system_ext_specific: true,
    system_ext_specific: true,
    libs: ["framework", "androidx.annotation_annotation",],
    libs: [
    required: ["androidx.window.extensions.xml",],
        "framework",
        "androidx.annotation_annotation",
    ],
    required: ["androidx.window.extensions.xml"],
}
}


prebuilt_etc {
prebuilt_etc {
+128 −0
Original line number Original line Diff line number Diff line
/*
 * 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 static androidx.window.util.ExtensionHelper.isZero;

import android.annotation.Nullable;
import android.graphics.Rect;

import androidx.annotation.NonNull;

import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/** Wrapper for both Extension and Sidecar versions of DisplayFeature. */
final class CommonDisplayFeature implements DisplayFeature {
    private static final Pattern FEATURE_PATTERN =
            Pattern.compile("([a-z]+)-\\[(\\d+),(\\d+),(\\d+),(\\d+)]");

    private static final String FEATURE_TYPE_FOLD = "fold";
    private static final String FEATURE_TYPE_HINGE = "hinge";

    // TODO(b/183049815): Support feature strings that include the state of the feature.
    /**
     * Parses a display feature from a string.
     *
     * @throws IllegalArgumentException if the provided string is improperly formatted or could not
     * otherwise be parsed.
     *
     * @see #FEATURE_PATTERN
     */
    @NonNull
    static CommonDisplayFeature parseFromString(@NonNull String string) {
        Matcher featureMatcher = FEATURE_PATTERN.matcher(string);
        if (!featureMatcher.matches()) {
            throw new IllegalArgumentException("Malformed feature description format: " + string);
        }
        try {
            String featureType = featureMatcher.group(1);
            int type;
            switch (featureType) {
                case FEATURE_TYPE_FOLD:
                    type = 1 /* TYPE_FOLD */;
                    break;
                case FEATURE_TYPE_HINGE:
                    type = 2 /* TYPE_HINGE */;
                    break;
                default: {
                    throw new IllegalArgumentException("Malformed feature type: " + featureType);
                }
            }

            int left = Integer.parseInt(featureMatcher.group(2));
            int top = Integer.parseInt(featureMatcher.group(3));
            int right = Integer.parseInt(featureMatcher.group(4));
            int bottom = Integer.parseInt(featureMatcher.group(5));
            Rect featureRect = new Rect(left, top, right, bottom);
            if (isZero(featureRect)) {
                throw new IllegalArgumentException("Feature has empty bounds: " + string);
            }

            return new CommonDisplayFeature(type, null, featureRect);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("Malformed feature description: " + string, e);
        }
    }

    private final int mType;
    @Nullable
    private final Integer mState;
    @NonNull
    private final Rect mRect;

    CommonDisplayFeature(int type, @Nullable Integer state, @NonNull Rect rect) {
        this.mType = type;
        this.mState = state;
        if (rect.width() == 0 && rect.height() == 0) {
            throw new IllegalArgumentException(
                    "Display feature rectangle cannot have zero width and height simultaneously.");
        }
        this.mRect = rect;
    }

    public int getType() {
        return mType;
    }

    /** Returns the state of the feature, or {@code null} if the feature has no state. */
    @Nullable
    public Integer getState() {
        return mState;
    }

    @NonNull
    public Rect getRect() {
        return mRect;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        CommonDisplayFeature that = (CommonDisplayFeature) o;
        return mType == that.mType
                && Objects.equals(mState, that.mState)
                && mRect.equals(that.mRect);
    }

    @Override
    public int hashCode() {
        return Objects.hash(mType, mState, mRect);
    }
}
+10 −26
Original line number Original line Diff line number Diff line
@@ -14,39 +14,23 @@
 * limitations under the License.
 * limitations under the License.
 */
 */


package androidx.window.util;
package androidx.window.common;


import android.annotation.Nullable;
import android.graphics.Rect;
import android.graphics.Rect;


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


/** Wrapper for both Extension and Sidecar versions of DisplayFeature. */
/** Wrapper for both Extension and Sidecar versions of DisplayFeature. */
public class BaseDisplayFeature {
public interface DisplayFeature {
    private final int mType;
    /** Returns the type of the feature. */
    private final int mState;
    int getType();
    @NonNull
    public final Rect mRect;

    public BaseDisplayFeature(int type, int state, @NonNull Rect rect) {
        this.mType = type;
        this.mState = state;
        if (rect.width() == 0 && rect.height() == 0) {
            throw new IllegalArgumentException(
                    "Display feature rectangle cannot have zero width and height simultaneously.");
        }
        this.mRect = rect;
    }


    public int getType() {
    /** Returns the state of the feature, or {@code null} if the feature has no state. */
        return mType;
    @Nullable
    }
    Integer getState();

    public int getState() {
        return mState;
    }


    /** Returns the bounds of the feature. */
    @NonNull
    @NonNull
    public Rect getRect() {
    Rect getRect();
        return mRect;
    }
}
}
+74 −0
Original line number Original line Diff line number Diff line
/*
 * 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);
    }
}
+96 −0
Original line number Original line Diff line number Diff line
/*
 * 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();
            }
        }
    }
}
Loading