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

Commit 9043bddf authored by Bryce Lee's avatar Bryce Lee Committed by Android (Google) Code Review
Browse files

Merge "IDreamOverlay Introduction."

parents 8c0a9894 87a5024e
Loading
Loading
Loading
Loading
+94 −0
Original line number Diff line number Diff line
@@ -26,7 +26,10 @@ import android.app.ActivityTaskManager;
import android.app.AlarmManager;
import android.app.Service;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
@@ -58,6 +61,8 @@ import com.android.internal.util.DumpUtils.Dump;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.function.Consumer;

/**
 * Extend this class to implement a custom dream (available to the user as a "Daydream").
@@ -169,6 +174,13 @@ public class DreamService extends Service implements Window.Callback {
    public static final String SERVICE_INTERFACE =
            "android.service.dreams.DreamService";

    /**
     * The name of the extra where the dream overlay component is stored.
     * @hide
     */
    public static final String EXTRA_DREAM_OVERLAY_COMPONENT =
            "android.service.dream.DreamService.dream_overlay_component";

    /**
     * Name under which a Dream publishes information about itself.
     * This meta-data must reference an XML resource containing
@@ -191,6 +203,7 @@ public class DreamService extends Service implements Window.Callback {
    private boolean mCanDoze;
    private boolean mDozing;
    private boolean mWindowless;
    private boolean mOverlayServiceBound;
    private int mDozeScreenState = Display.STATE_UNKNOWN;
    private int mDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;

@@ -199,8 +212,62 @@ public class DreamService extends Service implements Window.Callback {
    private DreamServiceWrapper mDreamServiceWrapper;
    private Runnable mDispatchAfterOnAttachedToWindow;

    private OverlayConnection mOverlayConnection;

    private static class OverlayConnection implements ServiceConnection {
        // Overlay set during onBind.
        private IDreamOverlay mOverlay;
        // A Queue of pending requests to execute on the overlay.
        private ArrayDeque<Consumer<IDreamOverlay>> mRequests;

        OverlayConnection() {
            mRequests = new ArrayDeque<>();
        }

        public void request(Consumer<IDreamOverlay> request) {
            mRequests.push(request);
            evaluate();
        }

        private void evaluate() {
            if (mOverlay == null) {
                return;
            }

            // Any new requests that arrive during this loop will be processed synchronously after
            // the loop exits.
            while (!mRequests.isEmpty()) {
                final Consumer<IDreamOverlay> request = mRequests.pop();
                request.accept(mOverlay);
            }
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // Store Overlay and execute pending requests.
            mOverlay = IDreamOverlay.Stub.asInterface(service);
            evaluate();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // Clear Overlay binder to prevent further request processing.
            mOverlay = null;
        }
    }

    private IDreamOverlayCallback mOverlayCallback = new IDreamOverlayCallback.Stub() {
        @Override
        public void onExitRequested() {
            // Simply finish dream when exit is requested.
            finish();
        }
    };


    public DreamService() {
        mDreamManager = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
        mOverlayConnection = new OverlayConnection();
    }

    /**
@@ -861,6 +928,18 @@ public class DreamService extends Service implements Window.Callback {
    public final IBinder onBind(Intent intent) {
        if (mDebug) Slog.v(TAG, "onBind() intent = " + intent);
        mDreamServiceWrapper = new DreamServiceWrapper();

        // Connect to the overlay service if present.
        final ComponentName overlayComponent =
                intent.getParcelableExtra(EXTRA_DREAM_OVERLAY_COMPONENT);
        if (overlayComponent != null && !mWindowless) {
            final Intent overlayIntent = new Intent();
            overlayIntent.setComponent(overlayComponent);

            mOverlayServiceBound = getApplicationContext().bindService(overlayIntent,
                    mOverlayConnection, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE);
        }

        return mDreamServiceWrapper;
    }

@@ -894,6 +973,11 @@ public class DreamService extends Service implements Window.Callback {
            return;
        }

        if (!mWindowless && mOverlayServiceBound) {
            unbindService(mOverlayConnection);
            mOverlayServiceBound = false;
        }

        try {
            // finishSelf will unbind the dream controller from the dream service. This will
            // trigger DreamService.this.onDestroy and DreamService.this will die.
@@ -1101,6 +1185,16 @@ public class DreamService extends Service implements Window.Callback {
                        }
                    }
                });

        // Request the DreamOverlay be told to dream with dream's window parameters once the service
        // has connected.
        mOverlayConnection.request(overlay -> {
            try {
                overlay.startDream(mWindow.getAttributes(), mOverlayCallback);
            } catch (RemoteException e) {
                Log.e(TAG, "could not send window attributes:" + e);
            }
        });
    }

    private boolean getWindowFlagValue(int flag, boolean defaultValue) {
+1 −0
Original line number Diff line number Diff line
@@ -41,4 +41,5 @@ interface IDreamManager {
    void forceAmbientDisplayEnabled(boolean enabled);
    ComponentName[] getDreamComponentsForUser(int userId);
    void setDreamComponentsForUser(int userId, in ComponentName[] componentNames);
    void registerDreamOverlayService(in ComponentName componentName);
}
+37 −0
Original line number 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 android.service.dreams;

import android.service.dreams.IDreamOverlayCallback;
import android.view.WindowManager.LayoutParams;

/**
* {@link IDreamOverlay} provides a way for a component to annotate a dream with additional view
* elements. Registered through the DreamManager, a IDreamOverlay is bound to by the dream and
* passed the necessary window details to participate in the user interface.

* @hide
*/
interface IDreamOverlay {
    /**
    * @param params The {@link LayoutParams} for the associated DreamWindow, including the window
                    token of the Dream Activity.
    * @param callback The {@link IDreamOverlayCallback} for requesting actions such as exiting the
    *                 dream.
    */
    void startDream(in LayoutParams params, in IDreamOverlayCallback callback);
}
+31 −0
Original line number 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 android.service.dreams;

/**
* {@link IDreamOverlayCallback} defines the interactions a dream overlay can have with its
* associated dream. It is the discretion of the {@link DreamService}) to honor any inbound requests
* from this callback.
*
* @hide
*/
interface IDreamOverlayCallback {
    /**
    * Invoked to request the dream exit.
    */
    void onExitRequested();
}
 No newline at end of file
+3 −1
Original line number Diff line number Diff line
@@ -117,7 +117,8 @@ final class DreamController {
    }

    public void startDream(Binder token, ComponentName name,
            boolean isTest, boolean canDoze, int userId, PowerManager.WakeLock wakeLock) {
            boolean isTest, boolean canDoze, int userId, PowerManager.WakeLock wakeLock,
            ComponentName overlayComponentName) {
        stopDream(true /*immediate*/, "starting new dream");

        Trace.traceBegin(Trace.TRACE_TAG_POWER, "startDream");
@@ -138,6 +139,7 @@ final class DreamController {
            Intent intent = new Intent(DreamService.SERVICE_INTERFACE);
            intent.setComponent(name);
            intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
            intent.putExtra(DreamService.EXTRA_DREAM_OVERLAY_COMPONENT, overlayComponentName);
            try {
                if (!mContext.bindServiceAsUser(intent, mCurrentDream,
                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
Loading