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

Commit bfd6be48 authored by Song Hu's avatar Song Hu
Browse files

Add new method 'requestServiceFeatures' in AppPredictionService. It allows...

Add new method 'requestServiceFeatures' in AppPredictionService. It allows Frontend to get backend service impl features info (e.g. feature readiness)

Bug: 292565550
Test: atest AppPredictionServiceTest
Change-Id: I0f2ec9ba0c1b332fa73afb461c29fe25de9b01e2
parent 39255ff4
Loading
Loading
Loading
Loading
+15 −0
Original line number Original line Diff line number Diff line
@@ -48,6 +48,7 @@ aconfig_srcjars = [
    ":android.service.controls.flags-aconfig-java{.generated_srcjars}",
    ":android.service.controls.flags-aconfig-java{.generated_srcjars}",
    ":android.service.dreams.flags-aconfig-java{.generated_srcjars}",
    ":android.service.dreams.flags-aconfig-java{.generated_srcjars}",
    ":android.service.notification.flags-aconfig-java{.generated_srcjars}",
    ":android.service.notification.flags-aconfig-java{.generated_srcjars}",
    ":android.service.appprediction.flags-aconfig-java{.generated_srcjars}",
    ":android.service.voice.flags-aconfig-java{.generated_srcjars}",
    ":android.service.voice.flags-aconfig-java{.generated_srcjars}",
    ":android.speech.flags-aconfig-java{.generated_srcjars}",
    ":android.speech.flags-aconfig-java{.generated_srcjars}",
    ":android.tracing.flags-aconfig-java{.generated_srcjars}",
    ":android.tracing.flags-aconfig-java{.generated_srcjars}",
@@ -112,6 +113,7 @@ stubs_defaults {
        "android.provider.flags-aconfig",
        "android.provider.flags-aconfig",
        "android.security.flags-aconfig",
        "android.security.flags-aconfig",
        "android.server.app.flags-aconfig",
        "android.server.app.flags-aconfig",
        "android.service.appprediction.flags-aconfig",
        "android.service.autofill.flags-aconfig",
        "android.service.autofill.flags-aconfig",
        "android.service.chooser.flags-aconfig",
        "android.service.chooser.flags-aconfig",
        "android.service.controls.flags-aconfig",
        "android.service.controls.flags-aconfig",
@@ -698,6 +700,19 @@ java_aconfig_library {
    defaults: ["framework-minus-apex-aconfig-java-defaults"],
    defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
}


// App prediction
aconfig_declarations {
    name: "android.service.appprediction.flags-aconfig",
    package: "android.service.appprediction.flags",
    srcs: ["core/java/android/service/appprediction/flags/*.aconfig"],
}

java_aconfig_library {
    name: "android.service.appprediction.flags-aconfig-java",
    aconfig_declarations: "android.service.appprediction.flags-aconfig",
    defaults: ["framework-minus-apex-aconfig-java-defaults"],
}

// Controls
// Controls
aconfig_declarations {
aconfig_declarations {
    name: "android.service.controls.flags-aconfig",
    name: "android.service.controls.flags-aconfig",
+2 −0
Original line number Original line Diff line number Diff line
@@ -2193,6 +2193,7 @@ package android.app.prediction {
    method public void notifyLaunchLocationShown(@NonNull String, @NonNull java.util.List<android.app.prediction.AppTargetId>);
    method public void notifyLaunchLocationShown(@NonNull String, @NonNull java.util.List<android.app.prediction.AppTargetId>);
    method public void registerPredictionUpdates(@NonNull java.util.concurrent.Executor, @NonNull android.app.prediction.AppPredictor.Callback);
    method public void registerPredictionUpdates(@NonNull java.util.concurrent.Executor, @NonNull android.app.prediction.AppPredictor.Callback);
    method public void requestPredictionUpdate();
    method public void requestPredictionUpdate();
    method @FlaggedApi("android.service.appprediction.flags.service_features_api") public void requestServiceFeatures(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.os.Bundle>);
    method @Nullable public void sortTargets(@NonNull java.util.List<android.app.prediction.AppTarget>, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<android.app.prediction.AppTarget>>);
    method @Nullable public void sortTargets(@NonNull java.util.List<android.app.prediction.AppTarget>, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<android.app.prediction.AppTarget>>);
    method public void unregisterPredictionUpdates(@NonNull android.app.prediction.AppPredictor.Callback);
    method public void unregisterPredictionUpdates(@NonNull android.app.prediction.AppPredictor.Callback);
  }
  }
@@ -11833,6 +11834,7 @@ package android.service.appprediction {
    method @MainThread public void onDestroyPredictionSession(@NonNull android.app.prediction.AppPredictionSessionId);
    method @MainThread public void onDestroyPredictionSession(@NonNull android.app.prediction.AppPredictionSessionId);
    method @MainThread public abstract void onLaunchLocationShown(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull String, @NonNull java.util.List<android.app.prediction.AppTargetId>);
    method @MainThread public abstract void onLaunchLocationShown(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull String, @NonNull java.util.List<android.app.prediction.AppTargetId>);
    method @MainThread public abstract void onRequestPredictionUpdate(@NonNull android.app.prediction.AppPredictionSessionId);
    method @MainThread public abstract void onRequestPredictionUpdate(@NonNull android.app.prediction.AppPredictionSessionId);
    method @FlaggedApi("android.service.appprediction.flags.service_features_api") @MainThread public void onRequestServiceFeatures(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull java.util.function.Consumer<android.os.Bundle>);
    method @MainThread public abstract void onSortAppTargets(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull java.util.List<android.app.prediction.AppTarget>, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<java.util.List<android.app.prediction.AppTarget>>);
    method @MainThread public abstract void onSortAppTargets(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull java.util.List<android.app.prediction.AppTarget>, @NonNull android.os.CancellationSignal, @NonNull java.util.function.Consumer<java.util.List<android.app.prediction.AppTarget>>);
    method @MainThread public void onStartPredictionUpdates();
    method @MainThread public void onStartPredictionUpdates();
    method @MainThread public void onStopPredictionUpdates();
    method @MainThread public void onStopPredictionUpdates();
+54 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@
package android.app.prediction;
package android.app.prediction;


import android.annotation.CallbackExecutor;
import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.SystemApi;
@@ -24,9 +25,12 @@ import android.app.prediction.IPredictionCallback.Stub;
import android.content.Context;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.content.pm.ParceledListSlice;
import android.os.Binder;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager;
import android.service.appprediction.flags.Flags;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Log;


@@ -262,6 +266,34 @@ public final class AppPredictor {
        }
        }
    }
    }


    /**
     * Requests a Bundle which includes service features info or {@code null} if the service is not
     * available.
     *
     * @param callbackExecutor The callback executor to use when calling the callback. It cannot be
     *                        null.
     * @param callback The callback to return the Bundle which includes service features info. It
     *                cannot be null.
     *
     * @throws IllegalStateException If this AppPredictor has already been destroyed.
     * @throws RuntimeException If there is a failure communicating with the remote service.
     */
    @FlaggedApi(Flags.FLAG_SERVICE_FEATURES_API)
    public void requestServiceFeatures(@NonNull Executor callbackExecutor,
            @NonNull Consumer<Bundle> callback) {
        if (mIsClosed.get()) {
            throw new IllegalStateException("This client has already been destroyed.");
        }

        try {
            mPredictionManager.requestServiceFeatures(mSessionId,
                    new RemoteCallbackWrapper(callbackExecutor, callback));
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to request service feature info", e);
            e.rethrowAsRuntimeException();
        }
    }

    /**
    /**
     * Destroys the client and unregisters the callback. Any method on this class after this call
     * Destroys the client and unregisters the callback. Any method on this class after this call
     * with throw {@link IllegalStateException}.
     * with throw {@link IllegalStateException}.
@@ -347,6 +379,28 @@ public final class AppPredictor {
        }
        }
    }
    }


    static class RemoteCallbackWrapper extends IRemoteCallback.Stub {

        private final Consumer<Bundle> mCallback;
        private final Executor mExecutor;

        RemoteCallbackWrapper(@NonNull Executor callbackExecutor,
                @NonNull Consumer<Bundle> callback) {
            mExecutor = callbackExecutor;
            mCallback = callback;
        }

        @Override
        public void sendResult(Bundle result) {
            final long identity = Binder.clearCallingIdentity();
            try {
                mExecutor.execute(() -> mCallback.accept(result));
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }
    }

    private static class Token {
    private static class Token {
        static final IBinder sBinder = new Binder(TAG);
        static final IBinder sBinder = new Binder(TAG);
    }
    }
+3 −0
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@ import android.app.prediction.AppPredictionContext;
import android.app.prediction.AppPredictionSessionId;
import android.app.prediction.AppPredictionSessionId;
import android.app.prediction.IPredictionCallback;
import android.app.prediction.IPredictionCallback;
import android.content.pm.ParceledListSlice;
import android.content.pm.ParceledListSlice;
import android.os.IRemoteCallback;


/**
/**
 * @hide
 * @hide
@@ -48,4 +49,6 @@ interface IPredictionManager {
    void requestPredictionUpdate(in AppPredictionSessionId sessionId);
    void requestPredictionUpdate(in AppPredictionSessionId sessionId);


    void onDestroyPredictionSession(in AppPredictionSessionId sessionId);
    void onDestroyPredictionSession(in AppPredictionSessionId sessionId);

    void requestServiceFeatures(in AppPredictionSessionId sessionId, in IRemoteCallback callback);
}
}
+72 −0
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@ package android.service.appprediction;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;


import android.annotation.CallSuper;
import android.annotation.CallSuper;
import android.annotation.FlaggedApi;
import android.annotation.MainThread;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
@@ -31,12 +32,15 @@ import android.app.prediction.AppTargetId;
import android.app.prediction.IPredictionCallback;
import android.app.prediction.IPredictionCallback;
import android.content.Intent;
import android.content.Intent;
import android.content.pm.ParceledListSlice;
import android.content.pm.ParceledListSlice;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.Looper;
import android.os.RemoteException;
import android.os.RemoteException;
import android.service.appprediction.IPredictionService.Stub;
import android.service.appprediction.IPredictionService.Stub;
import android.service.appprediction.flags.Flags;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Log;
import android.util.Slog;
import android.util.Slog;
@@ -134,6 +138,16 @@ public abstract class AppPredictionService extends Service {
                    obtainMessage(AppPredictionService::doDestroyPredictionSession,
                    obtainMessage(AppPredictionService::doDestroyPredictionSession,
                            AppPredictionService.this, sessionId));
                            AppPredictionService.this, sessionId));
        }
        }

        @FlaggedApi(Flags.FLAG_SERVICE_FEATURES_API)
        @Override
        public void requestServiceFeatures(AppPredictionSessionId sessionId,
                IRemoteCallback callback) {
            mHandler.sendMessage(
                    obtainMessage(AppPredictionService::onRequestServiceFeatures,
                            AppPredictionService.this, sessionId,
                            new RemoteCallbackWrapper(callback, null)));
        }
    };
    };


    @CallSuper
    @CallSuper
@@ -276,6 +290,18 @@ public abstract class AppPredictionService extends Service {
    @MainThread
    @MainThread
    public void onDestroyPredictionSession(@NonNull AppPredictionSessionId sessionId) {}
    public void onDestroyPredictionSession(@NonNull AppPredictionSessionId sessionId) {}


    /**
     * Called by the client app to request {@link AppPredictionService} features info.
     *
     * @param sessionId the session's Id. It is @NonNull.
     * @param callback the callback to return the Bundle which includes service features info. It
     *                is @NonNull.
     */
    @FlaggedApi(Flags.FLAG_SERVICE_FEATURES_API)
    @MainThread
    public void onRequestServiceFeatures(@NonNull AppPredictionSessionId sessionId,
            @NonNull Consumer<Bundle> callback) {}

    /**
    /**
     * Used by the prediction factory to send back results the client app. The can be called
     * Used by the prediction factory to send back results the client app. The can be called
     * in response to {@link #onRequestPredictionUpdate(AppPredictionSessionId)} or proactively as
     * in response to {@link #onRequestPredictionUpdate(AppPredictionSessionId)} or proactively as
@@ -357,4 +383,50 @@ public abstract class AppPredictionService extends Service {
            }
            }
        }
        }
    }
    }

    private static final class RemoteCallbackWrapper implements Consumer<Bundle>,
            IBinder.DeathRecipient {

        private IRemoteCallback mCallback;
        private final Consumer<RemoteCallbackWrapper> mOnBinderDied;

        RemoteCallbackWrapper(IRemoteCallback callback,
                @Nullable Consumer<RemoteCallbackWrapper> onBinderDied) {
            mCallback = callback;
            mOnBinderDied = onBinderDied;
            if (mOnBinderDied != null) {
                try {
                    mCallback.asBinder().linkToDeath(this, 0);
                } catch (RemoteException e) {
                    Slog.e(TAG, "Failed to link to death: " + e);
                }
            }
        }

        public void destroy() {
            if (mCallback != null && mOnBinderDied != null) {
                mCallback.asBinder().unlinkToDeath(this, 0);
            }
        }

        @Override
        public void accept(Bundle bundle) {
            try {
                if (mCallback != null) {
                    mCallback.sendResult(bundle);
                }
            } catch (RemoteException e) {
                Slog.e(TAG, "Error sending result:" + e);
            }
        }

        @Override
        public void binderDied() {
            destroy();
            mCallback = null;
            if (mOnBinderDied != null) {
                mOnBinderDied.accept(this);
            }
        }
    }
}
}
Loading