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

Commit c82d24e9 authored by Joe Antonetti's avatar Joe Antonetti Committed by Android (Google) Code Review
Browse files

Merge "Add onHandoffActivityDataRequested" into main

parents 64227ee8 f677d131
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -4592,6 +4592,7 @@ package android.app {
    method public void onEnterAnimationComplete();
    method public boolean onGenericMotionEvent(android.view.MotionEvent);
    method public void onGetDirectActions(@NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<java.util.List<android.app.DirectAction>>);
    method @FlaggedApi("android.companion.enable_task_continuity") @Nullable public android.app.HandoffActivityData onHandoffActivityDataRequested(@NonNull android.app.HandoffActivityDataRequestInfo);
    method public boolean onKeyDown(int, android.view.KeyEvent);
    method public boolean onKeyLongPress(int, android.view.KeyEvent);
    method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
@@ -6184,6 +6185,27 @@ package android.app {
    method public void setRequestedApplicationGrammaticalGender(int);
  }
  @FlaggedApi("android.companion.enable_task_continuity") public final class HandoffActivityData implements android.os.Parcelable {
    method public int describeContents();
    method @NonNull public android.content.ComponentName getComponentName();
    method @NonNull public android.os.PersistableBundle getExtras();
    method @Nullable public android.net.Uri getFallbackUri();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.app.HandoffActivityData> CREATOR;
  }
  @FlaggedApi("android.companion.enable_task_continuity") public static final class HandoffActivityData.Builder {
    ctor public HandoffActivityData.Builder(@NonNull android.content.ComponentName);
    method @NonNull public android.app.HandoffActivityData build();
    method @NonNull public android.app.HandoffActivityData.Builder setExtras(@NonNull android.os.PersistableBundle);
    method @NonNull public android.app.HandoffActivityData.Builder setFallbackUri(@Nullable android.net.Uri);
  }
  @FlaggedApi("android.companion.enable_task_continuity") public final class HandoffActivityDataRequestInfo {
    ctor public HandoffActivityDataRequestInfo(boolean);
    method public boolean isActiveRequest();
  }
  public class Instrumentation {
    ctor public Instrumentation();
    method public android.os.TestLooperManager acquireLooperManager(android.os.Looper);
+32 −0
Original line number Diff line number Diff line
@@ -10080,6 +10080,38 @@ public class Activity extends ContextThemeWrapper
        return mWindow.getOnBackInvokedDispatcher();
    }

    /**
     * Retrieves {@link HandoffActivityData} representing this activity, allowing it to be recreated
     * on another device owned by the user.
     *
     * The system automatically handles calling #onHandoffActivityDataRequested. This will only be
     * called if {@link #isHandoffEnabled} is {@code true} for this activity.
     *
     * If {@link #isHandoffEnabled} is {@code true}, the activity is expected to return a non-null
     * value. Returning {@code null} will present an error to the user indicating Handoff
     * unexpectedly failed.
     *
     * If the current activity is in the foreground on the current device, the app's icon
     * representing this activity will be shown on other nearby devices owned
     * by the user. If the user selects this icon, the system will call this method
     * to retrieve the data needed to recreate this activity on another device.
     *
     * When this activity is stopped, the system will call this method
     * to retrieve {@link HandoffActivityData} for caching. This allows the user
     * to hand this activity off to another device even if it is not currently
     * running. In these situations, {@link HandoffActivityDataRequestInfo#isActiveRequest}
     * will be {@code false}.
     *
     * @param requestInfo the request info for the activity data.
     * @return the activity data for handoff.
     */
    @FlaggedApi(android.companion.Flags.FLAG_ENABLE_TASK_CONTINUITY)
    @Nullable
    public HandoffActivityData onHandoffActivityDataRequested(
        @NonNull HandoffActivityDataRequestInfo requestInfo) {
      return null;
    }

    /**
     * Interface for observing screen captures of an {@link Activity}.
     */
+19 −0
Original line number Diff line number Diff line
/**
 * Copyright (c) 2025, 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.app;

parcelable HandoffActivityData;
 No newline at end of file
+206 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.app;

import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcelable;
import android.os.Parcel;
import android.net.Uri;
import android.os.PersistableBundle;
import android.os.Parcelable;
import android.content.ComponentName;
import android.util.Log;
import java.util.Objects;

/**
 * Represents information needed to recreate an activity on a remote device owned by the user.
 *
 * This class is returned by {@link Activity#onHandoffActivityDataRequested}, and is passed to a
 * remote device owned by the user. The remote device will create a launch intent for the activity
 * specified by {@link #getComponentName()}, passing along any extras specified by
 * {@link getExtras()}.
 *
 * If {@link #getComponentName()} cannot be launched on the remote device, developers can optionally
 * specify a fallback URI in {@link #setFallbackUri()}. The URI specified will be launched on the
 * remote device's web browser in this case. If no fallback URI is specified, the user will be
 * presented with an error. If the system is attempting to hand off the entire task, failure to
 * resolve {@link #getComponentName()} will result in only the top activity of the task being handed
 * off.
 */
@FlaggedApi(android.companion.Flags.FLAG_ENABLE_TASK_CONTINUITY)
public final class HandoffActivityData implements Parcelable {

    private @NonNull ComponentName mComponentName;
    private @NonNull PersistableBundle mExtras;
    private @Nullable Uri mFallbackUri;

    private HandoffActivityData(@NonNull Builder builder) {
        Objects.requireNonNull(builder);
        mComponentName = builder.mComponentName;
        mExtras = builder.mExtras;
        mFallbackUri = builder.mFallbackUri;
    }

    private HandoffActivityData(Parcel in) {
        mComponentName = ComponentName.CREATOR.createFromParcel(in);
        mExtras = in.readPersistableBundle(getClass().getClassLoader());
        if (in.readInt() != 0) {
            mFallbackUri = Uri.CREATOR.createFromParcel(in);
        }
    }

    public static final @NonNull Creator<HandoffActivityData> CREATOR = new Creator<>() {
        @Override
        public HandoffActivityData createFromParcel(Parcel in) {
            return new HandoffActivityData(in);
        }

        @Override
        public HandoffActivityData[] newArray(int size) {
            return new HandoffActivityData[size];
        }
    };

    /**
     * @return the component name of an activity to launch on the remote device
     * when the activity represented by this object is handed off.
     */
    @NonNull
    public ComponentName getComponentName() {
        return mComponentName;
    }

    /**
     * @return extras to pass inside the launch intent via {@link Intent#putExtras} for the
     * activity specified by {@link #getComponentName()} during handoff. This defaults to an empty
     * bundle.
     */
    @NonNull
    public PersistableBundle getExtras() {
        return mExtras;
    }

    /**
     * @return the URI which will be launched on the remote device's web browser if the activity
     * specified by {@link #getComponentName()} cannot be launched, or {@code null} if no fallback
     * URI was specified.
     */
    @Nullable
    public Uri getFallbackUri() {
        return mFallbackUri;
    }

    @Override
    public int hashCode() {
        return Objects.hash(mComponentName, mExtras, mFallbackUri);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof HandoffActivityData) {
            final HandoffActivityData other = (HandoffActivityData) obj;
            return Objects.equals(mComponentName, other.mComponentName)
                    && Objects.equals(mExtras, other.mExtras)
                    && Objects.equals(mFallbackUri, other.mFallbackUri);
        }
        return false;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        mComponentName.writeToParcel(dest, flags);
        dest.writePersistableBundle(mExtras);
        if (mFallbackUri != null) {
            dest.writeInt(1);
            mFallbackUri.writeToParcel(dest, flags);
        } else {
            dest.writeInt(0);
        }
    }

    /**
     * Builder for {@link HandoffActivityData}.
     */
    @FlaggedApi(android.companion.Flags.FLAG_ENABLE_TASK_CONTINUITY)
    public final static class Builder {
        @NonNull private ComponentName mComponentName;
        @NonNull private PersistableBundle mExtras;
        @Nullable private Uri mFallbackUri;

        /**
         * Creates a builder for the given component name.
         *
         * @param componentName the component name of the activity to be launched.
         */
        public Builder(@NonNull ComponentName componentName) {
            mComponentName = Objects.requireNonNull(componentName);
            mExtras = new PersistableBundle();
            mFallbackUri = null;
        }

        /**
         * Specifies which extras will be passed to the activity with name
         * {@link #getComponentName()} in its launch intent. This information
         * should allow the activity on the receiving devices to restore the
         * state of the activity on the sending device.
         *
         * If no extras are specified, the activity will be launched with an
         * empty bundle for extras.
         *
         * Any extras specified here must be safe to pass to another device, and
         * thus should not reference any device-specific information such as file
         * paths.
         *
         * @param extras the extras of the activity to be launched.
         * @return the builder.
         */
        @NonNull
        public Builder setExtras(@NonNull PersistableBundle extras) {
            mExtras = Objects.requireNonNull(extras);
            return this;
        }

        /**
         * Sets a fallback URI for this activity.
         *
         * @param fallbackUri the fallback uri.
         * @return the builder.
         */
        @NonNull
        public Builder setFallbackUri(@Nullable Uri fallbackUri) {
            mFallbackUri = fallbackUri;
            return this;
        }

        /**
         * Builds the {@link HandoffActivityData} object.
         *
         * @return the {@link HandoffActivityData} object.
         */
        @NonNull
        public HandoffActivityData build() {
            return new HandoffActivityData(this);
        }
    }
}
 No newline at end of file
+51 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.app;

import android.annotation.FlaggedApi;

/**
 * Represents a request made by the platform to hand off an activity. An instance
 * of this class is passed to {@link Activity#onHandoffActivityDataRequested}, and
 * it provides context about how the request was made - for instance, if the request
 * was initiated by a user action. This context is used by the activity to inform
 * the {@link HandoffActivityData} returned by {@link Activity#onHandoffActivityDataRequested}.
 */
@FlaggedApi(android.companion.Flags.FLAG_ENABLE_TASK_CONTINUITY)
public final class HandoffActivityDataRequestInfo {

    private boolean mIsActiveRequest;

    /*
     * Creates a new instance of {@link HandoffActivityDataRequestInfo}.
     *
     * @param isActiveRequest true if the request for {@link HandoffActivityData} was triggered by
     * a user action. Otherwise, this is a request to cache {@link HandoffActivityData} for future
     * use.
     */
    public HandoffActivityDataRequestInfo(boolean isActiveRequest) {
        mIsActiveRequest = isActiveRequest;
    }

    /**
     * @return true if the request for {@link HandoffActivityData} was triggered by a user action.
     * Otherwise, this is a request to cache {@link HandoffActivityData} for future use.
     */
    public boolean isActiveRequest() {
        return mIsActiveRequest;
    }
}
 No newline at end of file
Loading