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

Commit 866a8d2e authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Merge SampleSidecarImpl and StubSidecar." into main

parents 8b9bb07a f1425291
Loading
Loading
Loading
Loading
+84 −19
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 * Copyright (C) 2024 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.
@@ -16,6 +16,7 @@

package androidx.window.sidecar;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.Application;
@@ -23,8 +24,9 @@ import android.content.Context;
import android.hardware.devicestate.DeviceStateManager;
import android.os.Bundle;
import android.os.IBinder;
import android.util.ArraySet;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.window.common.BaseDataProducer;
import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
import androidx.window.common.EmptyLifecycleCallbacksAdapter;
@@ -33,17 +35,27 @@ import androidx.window.common.layout.CommonFoldingFeature;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * Reference implementation of androidx.window.sidecar OEM interface for use with
 * WindowManager Jetpack.
 * Basic implementation of the {@link SidecarInterface}. An OEM can choose to use it as the base
 * class for their implementation.
 */
class SampleSidecarImpl extends StubSidecar {
class SidecarImpl implements SidecarInterface {

    private static final String TAG = "WindowManagerSidecar";

    @Nullable
    private SidecarCallback mSidecarCallback;
    private final ArraySet<IBinder> mWindowLayoutChangeListenerTokens = new ArraySet<>();
    private boolean mDeviceStateChangeListenerRegistered;
    @NonNull
    private List<CommonFoldingFeature> mStoredFeatures = new ArrayList<>();

    SampleSidecarImpl(Context context) {
    SidecarImpl(Context context) {
        ((Application) context.getApplicationContext())
                .registerActivityLifecycleCallbacks(new NotifyOnConfigurationChanged());
                .registerActivityLifecycleCallbacks(new SidecarImpl.NotifyOnConfigurationChanged());
        RawFoldingFeatureProducer settingsFeatureProducer = new RawFoldingFeatureProducer(context);
        BaseDataProducer<List<CommonFoldingFeature>> foldingFeatureProducer =
                new DeviceStateManagerFoldingFeatureProducer(context,
@@ -53,11 +65,46 @@ class SampleSidecarImpl extends StubSidecar {
        foldingFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
    }

    private void setStoredFeatures(List<CommonFoldingFeature> storedFeatures) {
        mStoredFeatures = storedFeatures;
    @NonNull
    @Override
    public SidecarDeviceState getDeviceState() {
        return SidecarHelper.calculateDeviceState(mStoredFeatures);
    }

    @NonNull
    @Override
    public SidecarWindowLayoutInfo getWindowLayoutInfo(@NonNull IBinder windowToken) {
        return SidecarHelper.calculateWindowLayoutInfo(windowToken, mStoredFeatures);
    }

    @Override
    public void setSidecarCallback(@NonNull SidecarCallback sidecarCallback) {
        mSidecarCallback = sidecarCallback;
    }

    @Override
    public void onWindowLayoutChangeListenerAdded(@NonNull IBinder iBinder) {
        mWindowLayoutChangeListenerTokens.add(iBinder);
        onListenersChanged();
    }

    @Override
    public void onWindowLayoutChangeListenerRemoved(@NonNull IBinder iBinder) {
        mWindowLayoutChangeListenerTokens.remove(iBinder);
        onListenersChanged();
    }

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

    private void setStoredFeatures(@NonNull List<CommonFoldingFeature> storedFeatures) {
        mStoredFeatures = Objects.requireNonNull(storedFeatures);
    }

    private void onDisplayFeaturesChanged(List<CommonFoldingFeature> storedFeatures) {
    private void onDisplayFeaturesChanged(@NonNull List<CommonFoldingFeature> storedFeatures) {
        setStoredFeatures(storedFeatures);
        updateDeviceState(getDeviceState());
        for (IBinder windowToken : getWindowsListeningForLayoutChanges()) {
@@ -66,25 +113,43 @@ class SampleSidecarImpl extends StubSidecar {
        }
    }

    @NonNull
    @Override
    public SidecarDeviceState getDeviceState() {
        return SidecarHelper.calculateDeviceState(mStoredFeatures);
    void updateDeviceState(@NonNull SidecarDeviceState newState) {
        if (mSidecarCallback != null) {
            try {
                mSidecarCallback.onDeviceStateChanged(newState);
            } catch (AbstractMethodError e) {
                Log.e(TAG, "App is using an outdated Window Jetpack library", e);
            }
        }
    }

    void updateWindowLayout(@NonNull IBinder windowToken,
            @NonNull SidecarWindowLayoutInfo newLayout) {
        if (mSidecarCallback != null) {
            try {
                mSidecarCallback.onWindowLayoutChanged(windowToken, newLayout);
            } catch (AbstractMethodError e) {
                Log.e(TAG, "App is using an outdated Window Jetpack library", e);
            }
        }
    }

    @NonNull
    @Override
    public SidecarWindowLayoutInfo getWindowLayoutInfo(@NonNull IBinder windowToken) {
        return SidecarHelper.calculateWindowLayoutInfo(windowToken, mStoredFeatures);
    private Set<IBinder> getWindowsListeningForLayoutChanges() {
        return mWindowLayoutChangeListenerTokens;
    }

    @Override
    protected void onListenersChanged() {
    protected boolean hasListeners() {
        return !mWindowLayoutChangeListenerTokens.isEmpty() || mDeviceStateChangeListenerRegistered;
    }

    private void onListenersChanged() {
        if (hasListeners()) {
            onDisplayFeaturesChanged(mStoredFeatures);
        }
    }


    private final class NotifyOnConfigurationChanged extends EmptyLifecycleCallbacksAdapter {
        @Override
        public void onActivityCreated(@NonNull Activity activity,
+1 −1
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ public class SidecarProvider {
    @Nullable
    public static SidecarInterface getSidecarImpl(Context context) {
        return isWindowExtensionsEnabled()
                ? new SampleSidecarImpl(context.getApplicationContext())
                ? new SidecarImpl(context.getApplicationContext())
                : null;
    }

+0 −96
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.sidecar;

import android.os.IBinder;
import android.util.Log;

import androidx.annotation.NonNull;

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

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

    private static final String TAG = "WindowManagerSidecar";

    private SidecarCallback mSidecarCallback;
    final Set<IBinder> mWindowLayoutChangeListenerTokens = new HashSet<>();
    private boolean mDeviceStateChangeListenerRegistered;

    StubSidecar() {
    }

    @Override
    public void setSidecarCallback(@NonNull SidecarCallback sidecarCallback) {
        this.mSidecarCallback = sidecarCallback;
    }

    @Override
    public void onWindowLayoutChangeListenerAdded(@NonNull IBinder iBinder) {
        this.mWindowLayoutChangeListenerTokens.add(iBinder);
        this.onListenersChanged();
    }

    @Override
    public void onWindowLayoutChangeListenerRemoved(@NonNull IBinder iBinder) {
        this.mWindowLayoutChangeListenerTokens.remove(iBinder);
        this.onListenersChanged();
    }

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

    void updateDeviceState(SidecarDeviceState newState) {
        if (this.mSidecarCallback != null) {
            try {
                mSidecarCallback.onDeviceStateChanged(newState);
            } catch (AbstractMethodError e) {
                Log.e(TAG, "App is using an outdated Window Jetpack library", e);
            }
        }
    }

    void updateWindowLayout(@NonNull IBinder windowToken,
            @NonNull SidecarWindowLayoutInfo newLayout) {
        if (this.mSidecarCallback != null) {
            try {
                mSidecarCallback.onWindowLayoutChanged(windowToken, newLayout);
            } catch (AbstractMethodError e) {
                Log.e(TAG, "App is using an outdated Window Jetpack library", e);
            }
        }
    }

    @NonNull
    Set<IBinder> getWindowsListeningForLayoutChanges() {
        return mWindowLayoutChangeListenerTokens;
    }

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

    protected abstract void onListenersChanged();
}