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

Commit 90f1b95c authored by Andrii Kulian's avatar Andrii Kulian Committed by Android (Google) Code Review
Browse files

Merge "Add sample WM Jetpack Extensions impl" into sc-dev

parents 582247ee 336f9fdf
Loading
Loading
Loading
Loading
+30 −1
Original line number Original line Diff line number Diff line
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// See the License for the specific language governing permissions and
// limitations under the License.
// limitations under the License.


// Sidecar
android_library_import {
android_library_import {
    name: "window-sidecar",
    name: "window-sidecar",
    aars: ["window-sidecar-release.aar"],
    aars: ["window-sidecar-release.aar"],
@@ -20,7 +21,7 @@ android_library_import {


java_library {
java_library {
    name: "androidx.window.sidecar",
    name: "androidx.window.sidecar",
    srcs: ["src/**/*.java"],
    srcs: ["src/androidx/window/sidecar/**/*.java", "src/androidx/window/util/**/*.java"],
    static_libs: ["window-sidecar"],
    static_libs: ["window-sidecar"],
    installable: true,
    installable: true,
    sdk_version: "core_platform",
    sdk_version: "core_platform",
@@ -36,3 +37,31 @@ prebuilt_etc {
    src: "androidx.window.sidecar.xml",
    src: "androidx.window.sidecar.xml",
    filename_from_src: true,
    filename_from_src: true,
}
}

// Extensions
// NOTE: This module is still under active development and must not
// be used in production. Use 'androidx.window.sidecar' instead.
android_library_import {
    name: "window-extensions",
    aars: ["window-extensions-release.aar"],
    sdk_version: "current",
}

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

prebuilt_etc {
    name: "androidx.window.extensions.xml",
    system_ext_specific: true,
    sub_dir: "permissions",
    src: "androidx.window.extensions.xml",
    filename_from_src: true,
}
+21 −0
Original line number Original line Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ 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.
  -->
<permissions>
    <library
        name="androidx.window.extensions"
        file="/system_ext/framework/androidx.window.extensions.jar"/>
</permissions>
+41 −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.extensions;

import android.content.Context;

/**
 * Provider class that will instantiate the library implementation. It must be included in the
 * vendor library, and the vendor implementation must match the signature of this class.
 */
public class ExtensionProvider {
    /**
     * Provides a simple implementation of {@link ExtensionInterface} that can be replaced by
     * an OEM by overriding this method.
     */
    public static ExtensionInterface getExtensionImpl(Context context) {
        return new SampleExtensionImpl(context);
    }

    /**
     * The support library will use this method to check API version compatibility.
     * @return API version string in MAJOR.MINOR.PATCH-description format.
     */
    public static String getApiVersion() {
        return "1.0.0-settings_sample";
    }
}
+109 −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.extensions;

import static android.view.Display.DEFAULT_DISPLAY;

import static androidx.window.util.ExtensionHelper.rotateRectToDisplayRotation;
import static androidx.window.util.ExtensionHelper.transformToWindowSpaceRect;

import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.window.util.BaseDisplayFeature;
import androidx.window.util.SettingsConfigProvider;

import java.util.ArrayList;
import java.util.List;

/**
 * Reference implementation of androidx.window.extensions OEM interface for use with
 * WindowManager Jetpack.
 *
 * NOTE: This version is a work in progress and under active development. It MUST NOT be used in
 * production builds since the interface can still change before reaching stable version.
 * Please refer to {@link androidx.window.sidecar.SampleSidecarImpl} instead.
 */
class SampleExtensionImpl extends StubExtension implements
        SettingsConfigProvider.StateChangeCallback {
    private static final String TAG = "SampleExtension";

    private final SettingsConfigProvider mConfigProvider;

    SampleExtensionImpl(Context context) {
        mConfigProvider = new SettingsConfigProvider(context, this);
    }

    @Override
    public void onDevicePostureChanged() {
        updateDeviceState(new ExtensionDeviceState(mConfigProvider.getDeviceState()));
    }

    @Override
    public void onDisplayFeaturesChanged() {
        for (Activity activity : getActivitiesListeningForLayoutChanges()) {
            ExtensionWindowLayoutInfo newLayout = getWindowLayoutInfo(activity);
            updateWindowLayout(activity, newLayout);
        }
    }

    @NonNull
    private ExtensionWindowLayoutInfo getWindowLayoutInfo(@NonNull Activity activity) {
        List<ExtensionDisplayFeature> displayFeatures = getDisplayFeatures(activity);
        return new ExtensionWindowLayoutInfo(displayFeatures);
    }

    private List<ExtensionDisplayFeature> getDisplayFeatures(@NonNull Activity activity) {
        List<ExtensionDisplayFeature> features = new ArrayList<>();
        int displayId = activity.getDisplayId();
        if (displayId != DEFAULT_DISPLAY) {
            Log.w(TAG, "This sample doesn't support display features on secondary displays");
            return features;
        }

        if (activity.isInMultiWindowMode()) {
            // 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.
            return features;
        }

        List<BaseDisplayFeature> storedFeatures = mConfigProvider.getDisplayFeatures();
        for (BaseDisplayFeature baseFeature : storedFeatures) {
            Rect featureRect = baseFeature.getRect();
            rotateRectToDisplayRotation(displayId, featureRect);
            transformToWindowSpaceRect(activity, featureRect);
            features.add(new ExtensionFoldingFeature(featureRect, baseFeature.getType(),
                    baseFeature.getState()));
        }
        return features;
    }

    @Override
    protected void onListenersChanged() {
        if (hasListeners()) {
            mConfigProvider.registerObserversIfNeeded();
        } else {
            mConfigProvider.unregisterObserversIfNeeded();
        }

        onDevicePostureChanged();
        onDisplayFeaturesChanged();
    }
}
+86 −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.extensions;

import android.app.Activity;

import androidx.annotation.NonNull;

import java.util.HashSet;
import java.util.Set;

/**
 * Basic implementation of the {@link ExtensionInterface}. An OEM can choose to use it as the base
 * class for their implementation.
 */
abstract class StubExtension implements ExtensionInterface {

    private ExtensionCallback mExtensionCallback;
    private final Set<Activity> mWindowLayoutChangeListenerActivities = new HashSet<>();
    private boolean mDeviceStateChangeListenerRegistered;

    StubExtension() {
    }

    @Override
    public void setExtensionCallback(@NonNull ExtensionCallback extensionCallback) {
        this.mExtensionCallback = extensionCallback;
    }

    @Override
    public void onWindowLayoutChangeListenerAdded(@NonNull Activity activity) {
        this.mWindowLayoutChangeListenerActivities.add(activity);
        this.onListenersChanged();
    }

    @Override
    public void onWindowLayoutChangeListenerRemoved(@NonNull Activity activity) {
        this.mWindowLayoutChangeListenerActivities.remove(activity);
        this.onListenersChanged();
    }

    @Override
    public void onDeviceStateListenersChanged(boolean isEmpty) {
        this.mDeviceStateChangeListenerRegistered = !isEmpty;
        this.onListenersChanged();
    }

    void updateDeviceState(ExtensionDeviceState newState) {
        if (this.mExtensionCallback != null) {
            mExtensionCallback.onDeviceStateChanged(newState);
        }
    }

    void updateWindowLayout(@NonNull Activity activity,
            @NonNull ExtensionWindowLayoutInfo newLayout) {
        if (this.mExtensionCallback != null) {
            mExtensionCallback.onWindowLayoutChanged(activity, newLayout);
        }
    }

    @NonNull
    Set<Activity> getActivitiesListeningForLayoutChanges() {
        return mWindowLayoutChangeListenerActivities;
    }

    protected boolean hasListeners() {
        return !mWindowLayoutChangeListenerActivities.isEmpty()
                || mDeviceStateChangeListenerRegistered;
    }

    protected abstract void onListenersChanged();
}
Loading