Merge "Remove impl of cloudsearch api" into tm-qpr-dev
This commit is contained in:
@@ -29,8 +29,6 @@ import android.app.ambientcontext.AmbientContextManager;
|
||||
import android.app.ambientcontext.IAmbientContextManager;
|
||||
import android.app.appsearch.AppSearchManagerFrameworkInitializer;
|
||||
import android.app.blob.BlobStoreManagerFrameworkInitializer;
|
||||
import android.app.cloudsearch.CloudSearchManager;
|
||||
import android.app.cloudsearch.ICloudSearchManager;
|
||||
import android.app.contentsuggestions.ContentSuggestionsManager;
|
||||
import android.app.contentsuggestions.IContentSuggestionsManager;
|
||||
import android.app.job.JobSchedulerFrameworkInitializer;
|
||||
@@ -1231,17 +1229,6 @@ public final class SystemServiceRegistry {
|
||||
}
|
||||
});
|
||||
|
||||
registerService(Context.CLOUDSEARCH_SERVICE, CloudSearchManager.class,
|
||||
new CachedServiceFetcher<CloudSearchManager>() {
|
||||
@Override
|
||||
public CloudSearchManager createService(ContextImpl ctx)
|
||||
throws ServiceNotFoundException {
|
||||
IBinder b = ServiceManager.getService(Context.CLOUDSEARCH_SERVICE);
|
||||
return b == null ? null :
|
||||
new CloudSearchManager(ICloudSearchManager.Stub.asInterface(b));
|
||||
}
|
||||
});
|
||||
|
||||
registerService(Context.APP_PREDICTION_SERVICE, AppPredictionManager.class,
|
||||
new CachedServiceFetcher<AppPredictionManager>() {
|
||||
@Override
|
||||
|
||||
@@ -15,17 +15,15 @@
|
||||
*/
|
||||
package android.app.cloudsearch;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.SystemService;
|
||||
import android.content.Context;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* A {@link CloudSearchManager} is the class having all the information passed to search providers.
|
||||
*
|
||||
@@ -41,7 +39,7 @@ public class CloudSearchManager {
|
||||
/**
|
||||
* Invoked by receiving app with the result of the search.
|
||||
*
|
||||
* @param request original request for the search.
|
||||
* @param request original request for the search.
|
||||
* @param response search result.
|
||||
*/
|
||||
void onSearchSucceeded(@NonNull SearchRequest request, @NonNull SearchResponse response);
|
||||
@@ -51,17 +49,15 @@ public class CloudSearchManager {
|
||||
* Each failure is recorded. The client may receive a failure from one provider and
|
||||
* subsequently receive successful searches from other providers
|
||||
*
|
||||
* @param request original request for the search.
|
||||
* @param request original request for the search.
|
||||
* @param response search result.
|
||||
*/
|
||||
void onSearchFailed(@NonNull SearchRequest request, @NonNull SearchResponse response);
|
||||
}
|
||||
|
||||
private final ICloudSearchManager mService;
|
||||
|
||||
/** @hide **/
|
||||
public CloudSearchManager(@NonNull ICloudSearchManager service) {
|
||||
mService = service;
|
||||
public CloudSearchManager() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,10 +65,9 @@ public class CloudSearchManager {
|
||||
* to the designated cloud lookup services. After the lookup is done, the given
|
||||
* callback will be invoked by the system with the result or lack thereof.
|
||||
*
|
||||
* @param request request to be searched.
|
||||
* @param request request to be searched.
|
||||
* @param callbackExecutor where the callback is invoked.
|
||||
* @param callback invoked when the result is available.
|
||||
*
|
||||
* @param callback invoked when the result is available.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@@ -80,49 +75,8 @@ public class CloudSearchManager {
|
||||
public void search(@NonNull SearchRequest request,
|
||||
@NonNull @CallbackExecutor Executor callbackExecutor,
|
||||
@NonNull CallBack callback) {
|
||||
try {
|
||||
mService.search(
|
||||
requireNonNull(request),
|
||||
new CallBackWrapper(
|
||||
requireNonNull(request),
|
||||
requireNonNull(callback),
|
||||
requireNonNull(callbackExecutor)));
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
private final class CallBackWrapper extends
|
||||
ICloudSearchManagerCallback.Stub {
|
||||
@NonNull
|
||||
private final SearchRequest mSearchRequest;
|
||||
|
||||
@NonNull
|
||||
private final CallBack mCallback;
|
||||
|
||||
@NonNull
|
||||
private final Executor mCallbackExecutor;
|
||||
|
||||
CallBackWrapper(
|
||||
SearchRequest searchRequest,
|
||||
CallBack callback,
|
||||
Executor callbackExecutor) {
|
||||
mSearchRequest = searchRequest;
|
||||
mCallback = callback;
|
||||
mCallbackExecutor = callbackExecutor;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onSearchSucceeded(SearchResponse searchResponse) {
|
||||
mCallbackExecutor.execute(
|
||||
() -> mCallback.onSearchSucceeded(mSearchRequest, searchResponse));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSearchFailed(SearchResponse searchResponse) {
|
||||
mCallbackExecutor.execute(
|
||||
() -> mCallback.onSearchFailed(mSearchRequest, searchResponse));
|
||||
}
|
||||
callbackExecutor.execute(
|
||||
() -> callback.onSearchFailed(request,
|
||||
new SearchResponse.Builder(SearchResponse.SEARCH_STATUS_UNKNOWN).build()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2022, 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.cloudsearch;
|
||||
|
||||
import android.app.cloudsearch.SearchRequest;
|
||||
import android.app.cloudsearch.SearchResponse;
|
||||
import android.app.cloudsearch.ICloudSearchManagerCallback;
|
||||
|
||||
/**
|
||||
* Used by {@link CloudSearchManager} to tell system server to do search.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
oneway interface ICloudSearchManager {
|
||||
void search(in SearchRequest request, in ICloudSearchManagerCallback callBack);
|
||||
|
||||
void returnResults(in IBinder token, in String requestId,
|
||||
in SearchResponse response);
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2022, 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.cloudsearch;
|
||||
|
||||
import android.app.cloudsearch.SearchResponse;
|
||||
|
||||
|
||||
/**
|
||||
* Callback used by system server to notify invoker of {@link CloudSearchManager} of the result
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
oneway interface ICloudSearchManagerCallback {
|
||||
void onSearchSucceeded(in SearchResponse response);
|
||||
|
||||
void onSearchFailed(in SearchResponse response);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2022, 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.cloudsearch;
|
||||
|
||||
parcelable SearchRequest;
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package android.app.cloudsearch;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.StringDef;
|
||||
@@ -28,7 +26,6 @@ import android.os.Parcelable;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A {@link SearchRequest} is the data class having all the information passed to search providers.
|
||||
@@ -38,36 +35,6 @@ import java.util.Objects;
|
||||
@SystemApi
|
||||
public final class SearchRequest implements Parcelable {
|
||||
|
||||
/**
|
||||
* Query for search.
|
||||
*/
|
||||
@NonNull
|
||||
private final String mQuery;
|
||||
|
||||
/**
|
||||
* Expected result offset for pagination.
|
||||
*
|
||||
* The default value is 0.
|
||||
*/
|
||||
private final int mResultOffset;
|
||||
|
||||
/**
|
||||
* Expected search result number.
|
||||
*
|
||||
* The default value is 10.
|
||||
*/
|
||||
private final int mResultNumber;
|
||||
|
||||
/**
|
||||
* The max acceptable latency.
|
||||
*
|
||||
* The default value is 200 milliseconds.
|
||||
*/
|
||||
private final float mMaxLatencyMillis;
|
||||
|
||||
@Nullable
|
||||
private String mId = null;
|
||||
|
||||
/**
|
||||
* List of public static KEYS for the Bundle to mSearchConstraints. mSearchConstraints
|
||||
* contains various constraints specifying the search intent.
|
||||
@@ -76,121 +43,83 @@ public final class SearchRequest implements Parcelable {
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@StringDef(prefix = {"CONSTRAINT_"},
|
||||
value = {CONSTRAINT_IS_PRESUBMIT_SUGGESTION,
|
||||
CONSTRAINT_SEARCH_PROVIDER_FILTER})
|
||||
public @interface SearchConstraintKey {}
|
||||
/** If this is a presubmit suggestion, Boolean value expected.
|
||||
* presubmit is the input before the user finishes the entire query, i.e. push "ENTER" or
|
||||
* "SEARCH" button. After the user finishes the entire query, the behavior is postsubmit.
|
||||
value = {CONSTRAINT_IS_PRESUBMIT_SUGGESTION,
|
||||
CONSTRAINT_SEARCH_PROVIDER_FILTER})
|
||||
public @interface SearchConstraintKey {
|
||||
}
|
||||
|
||||
/**
|
||||
* If this is a presubmit suggestion, Boolean value expected.
|
||||
* presubmit is the input before the user finishes the entire query, i.e. push "ENTER" or
|
||||
* "SEARCH" button. After the user finishes the entire query, the behavior is postsubmit.
|
||||
*/
|
||||
public static final String CONSTRAINT_IS_PRESUBMIT_SUGGESTION =
|
||||
"android.app.cloudsearch.IS_PRESUBMIT_SUGGESTION";
|
||||
/** The target search provider list of package names(separated by ;), String value expected.
|
||||
/**
|
||||
* The target search provider list of package names(separated by ;), String value expected.
|
||||
* If this is not provided or its value is empty, then no filter will be applied.
|
||||
*/
|
||||
public static final String CONSTRAINT_SEARCH_PROVIDER_FILTER =
|
||||
"android.app.cloudsearch.SEARCH_PROVIDER_FILTER";
|
||||
|
||||
@NonNull
|
||||
private Bundle mSearchConstraints;
|
||||
|
||||
/** Auto set by system servier, and the caller cannot set it.
|
||||
*
|
||||
* The caller's package name.
|
||||
*
|
||||
*/
|
||||
@NonNull
|
||||
private String mCallerPackageName;
|
||||
|
||||
private SearchRequest(Parcel in) {
|
||||
this.mQuery = in.readString();
|
||||
this.mResultOffset = in.readInt();
|
||||
this.mResultNumber = in.readInt();
|
||||
this.mMaxLatencyMillis = in.readFloat();
|
||||
this.mSearchConstraints = in.readBundle();
|
||||
this.mId = in.readString();
|
||||
this.mCallerPackageName = in.readString();
|
||||
}
|
||||
|
||||
private SearchRequest(String query, int resultOffset, int resultNumber, float maxLatencyMillis,
|
||||
Bundle searchConstraints, String callerPackageName) {
|
||||
mQuery = query;
|
||||
mResultOffset = resultOffset;
|
||||
mResultNumber = resultNumber;
|
||||
mMaxLatencyMillis = maxLatencyMillis;
|
||||
mSearchConstraints = searchConstraints;
|
||||
mCallerPackageName = callerPackageName;
|
||||
private SearchRequest() {
|
||||
}
|
||||
|
||||
/** Returns the original query. */
|
||||
@NonNull
|
||||
public String getQuery() {
|
||||
return mQuery;
|
||||
return "";
|
||||
}
|
||||
|
||||
/** Returns the result offset. */
|
||||
public int getResultOffset() {
|
||||
return mResultOffset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Returns the expected number of search results. */
|
||||
public int getResultNumber() {
|
||||
return mResultNumber;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Returns the maximum latency requirement. */
|
||||
public float getMaxLatencyMillis() {
|
||||
return mMaxLatencyMillis;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Returns the search constraints. */
|
||||
@NonNull
|
||||
public Bundle getSearchConstraints() {
|
||||
return mSearchConstraints;
|
||||
return Bundle.EMPTY;
|
||||
}
|
||||
|
||||
/** Gets the caller's package name. */
|
||||
@NonNull
|
||||
public String getCallerPackageName() {
|
||||
return mCallerPackageName;
|
||||
return "";
|
||||
}
|
||||
|
||||
/** Returns the search request id, which is used to identify the request. */
|
||||
@NonNull
|
||||
public String getRequestId() {
|
||||
if (mId == null || mId.length() == 0) {
|
||||
mId = String.valueOf(toString().hashCode());
|
||||
}
|
||||
|
||||
return mId;
|
||||
return "";
|
||||
}
|
||||
|
||||
/** Sets the caller, and this will be set by the system server.
|
||||
/**
|
||||
* Sets the caller, and this will be set by the system server.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void setCallerPackageName(@NonNull String callerPackageName) {
|
||||
this.mCallerPackageName = callerPackageName;
|
||||
}
|
||||
|
||||
private SearchRequest(Builder b) {
|
||||
mQuery = requireNonNull(b.mQuery);
|
||||
mResultOffset = b.mResultOffset;
|
||||
mResultNumber = b.mResultNumber;
|
||||
mMaxLatencyMillis = b.mMaxLatencyMillis;
|
||||
mSearchConstraints = requireNonNull(b.mSearchConstraints);
|
||||
mCallerPackageName = requireNonNull(b.mCallerPackageName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Creator
|
||||
*
|
||||
*/
|
||||
@NonNull
|
||||
public static final Creator<SearchRequest> CREATOR = new Creator<SearchRequest>() {
|
||||
@Override
|
||||
public SearchRequest createFromParcel(Parcel p) {
|
||||
return new SearchRequest(p);
|
||||
return new SearchRequest();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -201,13 +130,6 @@ public final class SearchRequest implements Parcelable {
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeString(this.mQuery);
|
||||
dest.writeInt(this.mResultOffset);
|
||||
dest.writeInt(this.mResultNumber);
|
||||
dest.writeFloat(this.mMaxLatencyMillis);
|
||||
dest.writeBundle(this.mSearchConstraints);
|
||||
dest.writeString(getRequestId());
|
||||
dest.writeString(this.mCallerPackageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -217,44 +139,17 @@ public final class SearchRequest implements Parcelable {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SearchRequest that = (SearchRequest) obj;
|
||||
return Objects.equals(mQuery, that.mQuery)
|
||||
&& mResultOffset == that.mResultOffset
|
||||
&& mResultNumber == that.mResultNumber
|
||||
&& mMaxLatencyMillis == that.mMaxLatencyMillis
|
||||
&& Objects.equals(mSearchConstraints, that.mSearchConstraints)
|
||||
&& Objects.equals(mCallerPackageName, that.mCallerPackageName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
boolean isPresubmit =
|
||||
mSearchConstraints.containsKey(CONSTRAINT_IS_PRESUBMIT_SUGGESTION)
|
||||
&& mSearchConstraints.getBoolean(CONSTRAINT_IS_PRESUBMIT_SUGGESTION);
|
||||
|
||||
String searchProvider = "EMPTY";
|
||||
if (mSearchConstraints.containsKey(CONSTRAINT_SEARCH_PROVIDER_FILTER)) {
|
||||
searchProvider = mSearchConstraints.getString(CONSTRAINT_SEARCH_PROVIDER_FILTER);
|
||||
}
|
||||
|
||||
return String.format("SearchRequest: {query:%s,offset:%d;number:%d;max_latency:%f;"
|
||||
+ "is_presubmit:%b;search_provider:%s;callerPackageName:%s}", mQuery,
|
||||
mResultOffset, mResultNumber, mMaxLatencyMillis, isPresubmit, searchProvider,
|
||||
mCallerPackageName);
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mQuery, mResultOffset, mResultNumber, mMaxLatencyMillis,
|
||||
mSearchConstraints, mCallerPackageName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,87 +159,62 @@ public final class SearchRequest implements Parcelable {
|
||||
*/
|
||||
@SystemApi
|
||||
public static final class Builder {
|
||||
private String mQuery;
|
||||
private int mResultOffset;
|
||||
private int mResultNumber;
|
||||
private float mMaxLatencyMillis;
|
||||
private Bundle mSearchConstraints;
|
||||
private String mCallerPackageName;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param query the query for search.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public Builder(@NonNull String query) {
|
||||
mQuery = query;
|
||||
|
||||
mResultOffset = 0;
|
||||
mResultNumber = 10;
|
||||
mMaxLatencyMillis = 200;
|
||||
mSearchConstraints = Bundle.EMPTY;
|
||||
mCallerPackageName = "DEFAULT_CALLER";
|
||||
}
|
||||
|
||||
/** Sets the input query. */
|
||||
@NonNull
|
||||
public Builder setQuery(@NonNull String query) {
|
||||
this.mQuery = query;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the search result offset. */
|
||||
@NonNull
|
||||
public Builder setResultOffset(int resultOffset) {
|
||||
this.mResultOffset = resultOffset;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the expected number of search result. */
|
||||
@NonNull
|
||||
public Builder setResultNumber(int resultNumber) {
|
||||
this.mResultNumber = resultNumber;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the maximum acceptable search latency. */
|
||||
@NonNull
|
||||
public Builder setMaxLatencyMillis(float maxLatencyMillis) {
|
||||
this.mMaxLatencyMillis = maxLatencyMillis;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the search constraints, such as the user location, the search type(presubmit or
|
||||
* postsubmit), and the target search providers. */
|
||||
/**
|
||||
* Sets the search constraints, such as the user location, the search type(presubmit or
|
||||
* postsubmit), and the target search providers.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setSearchConstraints(@Nullable Bundle searchConstraints) {
|
||||
this.mSearchConstraints = searchConstraints;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the caller, and this will be set by the system server.
|
||||
/**
|
||||
* Sets the caller, and this will be set by the system server.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
@TestApi
|
||||
public Builder setCallerPackageName(@NonNull String callerPackageName) {
|
||||
this.mCallerPackageName = callerPackageName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Builds a SearchRequest based-on the given params. */
|
||||
@NonNull
|
||||
public SearchRequest build() {
|
||||
if (mQuery == null || mResultOffset < 0 || mResultNumber < 1 || mMaxLatencyMillis < 0
|
||||
|| mSearchConstraints == null) {
|
||||
throw new IllegalStateException("Please make sure all required args are valid.");
|
||||
}
|
||||
|
||||
return new SearchRequest(mQuery, mResultOffset, mResultNumber, mMaxLatencyMillis,
|
||||
mSearchConstraints, mCallerPackageName);
|
||||
return new SearchRequest();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2022, 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.cloudsearch;
|
||||
|
||||
parcelable SearchResponse;
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package android.app.cloudsearch;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
@@ -25,7 +23,6 @@ import android.os.Parcelable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A {@link SearchResponse} includes search results and associated meta information.
|
||||
@@ -37,77 +34,53 @@ public final class SearchResponse implements Parcelable {
|
||||
/** @hide */
|
||||
@IntDef(prefix = {"SEARCH_STATUS_"},
|
||||
value = {SEARCH_STATUS_UNKNOWN,
|
||||
SEARCH_STATUS_OK,
|
||||
SEARCH_STATUS_TIME_OUT,
|
||||
SEARCH_STATUS_NO_INTERNET})
|
||||
public @interface SearchStatusCode {}
|
||||
SEARCH_STATUS_OK,
|
||||
SEARCH_STATUS_TIME_OUT,
|
||||
SEARCH_STATUS_NO_INTERNET})
|
||||
public @interface SearchStatusCode {
|
||||
}
|
||||
|
||||
public static final int SEARCH_STATUS_UNKNOWN = -1;
|
||||
public static final int SEARCH_STATUS_OK = 0;
|
||||
public static final int SEARCH_STATUS_TIME_OUT = 1;
|
||||
public static final int SEARCH_STATUS_NO_INTERNET = 2;
|
||||
|
||||
private final int mStatusCode;
|
||||
|
||||
/** Auto set by system servier, and the provider cannot set it. */
|
||||
@NonNull
|
||||
private String mSource;
|
||||
|
||||
@NonNull
|
||||
private final List<SearchResult> mSearchResults;
|
||||
|
||||
private SearchResponse(Parcel in) {
|
||||
this.mStatusCode = in.readInt();
|
||||
this.mSource = in.readString();
|
||||
this.mSearchResults = in.createTypedArrayList(SearchResult.CREATOR);
|
||||
}
|
||||
|
||||
private SearchResponse(@SearchStatusCode int statusCode, String source,
|
||||
List<SearchResult> searchResults) {
|
||||
mStatusCode = statusCode;
|
||||
mSource = source;
|
||||
mSearchResults = searchResults;
|
||||
private SearchResponse() {
|
||||
}
|
||||
|
||||
/** Gets the search status code. */
|
||||
public int getStatusCode() {
|
||||
return mStatusCode;
|
||||
return SEARCH_STATUS_UNKNOWN;
|
||||
}
|
||||
|
||||
/** Gets the search provider package name. */
|
||||
@NonNull
|
||||
public String getSource() {
|
||||
return mSource;
|
||||
return "";
|
||||
}
|
||||
|
||||
/** Gets the search results, which can be empty. */
|
||||
@NonNull
|
||||
public List<SearchResult> getSearchResults() {
|
||||
return mSearchResults;
|
||||
return new ArrayList<SearchResult>();
|
||||
}
|
||||
|
||||
/** Sets the search provider, and this will be set by the system server.
|
||||
/**
|
||||
* Sets the search provider, and this will be set by the system server.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void setSource(@NonNull String source) {
|
||||
this.mSource = source;
|
||||
}
|
||||
|
||||
private SearchResponse(Builder b) {
|
||||
mStatusCode = b.mStatusCode;
|
||||
mSource = requireNonNull(b.mSource);
|
||||
mSearchResults = requireNonNull(b.mSearchResults);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see Creator
|
||||
*
|
||||
*/
|
||||
@NonNull public static final Creator<SearchResponse> CREATOR = new Creator<SearchResponse>() {
|
||||
@NonNull
|
||||
public static final Creator<SearchResponse> CREATOR = new Creator<SearchResponse>() {
|
||||
@Override
|
||||
public SearchResponse createFromParcel(Parcel p) {
|
||||
return new SearchResponse(p);
|
||||
return new SearchResponse();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -118,9 +91,6 @@ public final class SearchResponse implements Parcelable {
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeInt(this.mStatusCode);
|
||||
dest.writeString(this.mSource);
|
||||
dest.writeTypedList(this.mSearchResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -130,23 +100,12 @@ public final class SearchResponse implements Parcelable {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SearchResponse that = (SearchResponse) obj;
|
||||
return mStatusCode == that.mStatusCode
|
||||
&& Objects.equals(mSource, that.mSource)
|
||||
&& Objects.equals(mSearchResults, that.mSearchResults);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mStatusCode, mSource, mSearchResults);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,59 +115,40 @@ public final class SearchResponse implements Parcelable {
|
||||
*/
|
||||
@SystemApi
|
||||
public static final class Builder {
|
||||
private int mStatusCode;
|
||||
private String mSource;
|
||||
private List<SearchResult> mSearchResults;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param statusCode the search status code.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public Builder(@SearchStatusCode int statusCode) {
|
||||
mStatusCode = statusCode;
|
||||
|
||||
/** Init with a default value. */
|
||||
mSource = "DEFAULT";
|
||||
|
||||
mSearchResults = new ArrayList<SearchResult>();
|
||||
}
|
||||
|
||||
/** Sets the search status code. */
|
||||
@NonNull
|
||||
public Builder setStatusCode(@SearchStatusCode int statusCode) {
|
||||
this.mStatusCode = statusCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the search provider, and this will be set by the system server.
|
||||
/**
|
||||
* Sets the search provider, and this will be set by the system server.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setSource(@NonNull String source) {
|
||||
this.mSource = source;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the search results. */
|
||||
@NonNull
|
||||
public Builder setSearchResults(@NonNull List<SearchResult> searchResults) {
|
||||
this.mSearchResults = searchResults;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Builds a SearchResponse based-on the given parameters. */
|
||||
@NonNull
|
||||
public SearchResponse build() {
|
||||
if (mStatusCode < SEARCH_STATUS_UNKNOWN || mStatusCode > SEARCH_STATUS_NO_INTERNET
|
||||
|| mSearchResults == null) {
|
||||
throw new IllegalStateException("Please make sure all @NonNull args are assigned.");
|
||||
}
|
||||
|
||||
return new SearchResponse(mStatusCode, mSource, mSearchResults);
|
||||
return new SearchResponse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2022, 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.cloudsearch;
|
||||
|
||||
parcelable SearchResult;
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package android.app.cloudsearch;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.StringDef;
|
||||
import android.annotation.SuppressLint;
|
||||
@@ -27,7 +25,6 @@ import android.os.Parcelable;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A {@link SearchResult} includes all the information for one result item.
|
||||
@@ -37,17 +34,6 @@ import java.util.Objects;
|
||||
@SystemApi
|
||||
public final class SearchResult implements Parcelable {
|
||||
|
||||
/** Short content best describing the result item. */
|
||||
@NonNull
|
||||
private final String mTitle;
|
||||
|
||||
/** Matched contents in the result item. */
|
||||
@NonNull
|
||||
private final String mSnippet;
|
||||
|
||||
/** Ranking Score provided by the search provider. */
|
||||
private final float mScore;
|
||||
|
||||
/**
|
||||
* List of public static KEYS for Bundles in mExtraInfos.
|
||||
* mExtraInfos contains various information specified for different data types.
|
||||
@@ -56,28 +42,30 @@ public final class SearchResult implements Parcelable {
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@StringDef(prefix = {"EXTRAINFO_"},
|
||||
value = {EXTRAINFO_APP_DOMAIN_URL,
|
||||
EXTRAINFO_APP_ICON,
|
||||
EXTRAINFO_APP_DEVELOPER_NAME,
|
||||
EXTRAINFO_APP_SIZE_BYTES,
|
||||
EXTRAINFO_APP_STAR_RATING,
|
||||
EXTRAINFO_APP_IARC,
|
||||
EXTRAINFO_APP_REVIEW_COUNT,
|
||||
EXTRAINFO_APP_CONTAINS_ADS_DISCLAIMER,
|
||||
EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER,
|
||||
EXTRAINFO_SHORT_DESCRIPTION,
|
||||
EXTRAINFO_LONG_DESCRIPTION,
|
||||
EXTRAINFO_SCREENSHOTS,
|
||||
EXTRAINFO_APP_BADGES,
|
||||
EXTRAINFO_ACTION_BUTTON_TEXT_PREREGISTERING,
|
||||
EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING,
|
||||
EXTRAINFO_ACTION_APP_CARD,
|
||||
EXTRAINFO_ACTION_INSTALL_BUTTON,
|
||||
EXTRAINFO_APP_PACKAGE_NAME,
|
||||
EXTRAINFO_APP_INSTALL_COUNT,
|
||||
EXTRAINFO_WEB_URL,
|
||||
EXTRAINFO_WEB_ICON})
|
||||
public @interface SearchResultExtraInfoKey {}
|
||||
value = {EXTRAINFO_APP_DOMAIN_URL,
|
||||
EXTRAINFO_APP_ICON,
|
||||
EXTRAINFO_APP_DEVELOPER_NAME,
|
||||
EXTRAINFO_APP_SIZE_BYTES,
|
||||
EXTRAINFO_APP_STAR_RATING,
|
||||
EXTRAINFO_APP_IARC,
|
||||
EXTRAINFO_APP_REVIEW_COUNT,
|
||||
EXTRAINFO_APP_CONTAINS_ADS_DISCLAIMER,
|
||||
EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER,
|
||||
EXTRAINFO_SHORT_DESCRIPTION,
|
||||
EXTRAINFO_LONG_DESCRIPTION,
|
||||
EXTRAINFO_SCREENSHOTS,
|
||||
EXTRAINFO_APP_BADGES,
|
||||
EXTRAINFO_ACTION_BUTTON_TEXT_PREREGISTERING,
|
||||
EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING,
|
||||
EXTRAINFO_ACTION_APP_CARD,
|
||||
EXTRAINFO_ACTION_INSTALL_BUTTON,
|
||||
EXTRAINFO_APP_PACKAGE_NAME,
|
||||
EXTRAINFO_APP_INSTALL_COUNT,
|
||||
EXTRAINFO_WEB_URL,
|
||||
EXTRAINFO_WEB_ICON})
|
||||
public @interface SearchResultExtraInfoKey {
|
||||
}
|
||||
|
||||
/** This App developer website's domain URL, String value expected. */
|
||||
public static final String EXTRAINFO_APP_DOMAIN_URL = "android.app.cloudsearch.APP_DOMAIN_URL";
|
||||
/** This App icon, android.graphics.drawable.Icon expected. */
|
||||
@@ -90,7 +78,8 @@ public final class SearchResult implements Parcelable {
|
||||
/** This App developer's name, Double value expected. */
|
||||
public static final String EXTRAINFO_APP_STAR_RATING =
|
||||
"android.app.cloudsearch.APP_STAR_RATING";
|
||||
/** This App's IARC rating, String value expected.
|
||||
/**
|
||||
* This App's IARC rating, String value expected.
|
||||
* IARC (International Age Rating Coalition) is partnered globally with major
|
||||
* content rating organizations to provide a centralized and one-stop-shop for
|
||||
* rating content on a global scale.
|
||||
@@ -142,62 +131,40 @@ public final class SearchResult implements Parcelable {
|
||||
/** Web content's domain icon, android.graphics.drawable.Icon expected. */
|
||||
public static final String EXTRAINFO_WEB_ICON = "android.app.cloudsearch.WEB_ICON";
|
||||
|
||||
@NonNull
|
||||
private Bundle mExtraInfos;
|
||||
|
||||
private SearchResult(Parcel in) {
|
||||
this.mTitle = in.readString();
|
||||
this.mSnippet = in.readString();
|
||||
this.mScore = in.readFloat();
|
||||
this.mExtraInfos = in.readBundle();
|
||||
}
|
||||
|
||||
private SearchResult(String title, String snippet, float score, Bundle extraInfos) {
|
||||
mTitle = title;
|
||||
mSnippet = snippet;
|
||||
mScore = score;
|
||||
mExtraInfos = extraInfos;
|
||||
private SearchResult() {
|
||||
}
|
||||
|
||||
/** Gets the search result title. */
|
||||
@NonNull
|
||||
public String getTitle() {
|
||||
return mTitle;
|
||||
return "";
|
||||
}
|
||||
|
||||
/** Gets the search result snippet. */
|
||||
@NonNull
|
||||
public String getSnippet() {
|
||||
return mSnippet;
|
||||
return "";
|
||||
}
|
||||
|
||||
/** Gets the ranking score provided by the original search provider. */
|
||||
public float getScore() {
|
||||
return mScore;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Gets the extra information associated with the search result. */
|
||||
@NonNull
|
||||
public Bundle getExtraInfos() {
|
||||
return mExtraInfos;
|
||||
}
|
||||
|
||||
private SearchResult(Builder b) {
|
||||
mTitle = requireNonNull(b.mTitle);
|
||||
mSnippet = requireNonNull(b.mSnippet);
|
||||
mScore = b.mScore;
|
||||
mExtraInfos = requireNonNull(b.mExtraInfos);
|
||||
return Bundle.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see Creator
|
||||
*
|
||||
*/
|
||||
@NonNull public static final Creator<SearchResult> CREATOR = new Creator<SearchResult>() {
|
||||
@NonNull
|
||||
public static final Creator<SearchResult> CREATOR = new Creator<SearchResult>() {
|
||||
@Override
|
||||
public SearchResult createFromParcel(Parcel p) {
|
||||
return new SearchResult(p);
|
||||
return new SearchResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -208,10 +175,6 @@ public final class SearchResult implements Parcelable {
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeString(this.mTitle);
|
||||
dest.writeString(this.mSnippet);
|
||||
dest.writeFloat(this.mScore);
|
||||
dest.writeBundle(this.mExtraInfos);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -221,24 +184,12 @@ public final class SearchResult implements Parcelable {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SearchResult that = (SearchResult) obj;
|
||||
return Objects.equals(mTitle, that.mTitle)
|
||||
&& Objects.equals(mSnippet, that.mSnippet)
|
||||
&& mScore == that.mScore
|
||||
&& Objects.equals(mExtraInfos, that.mExtraInfos);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mTitle, mSnippet, mScore, mExtraInfos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -248,63 +199,43 @@ public final class SearchResult implements Parcelable {
|
||||
*/
|
||||
@SystemApi
|
||||
public static final class Builder {
|
||||
private String mTitle;
|
||||
private String mSnippet;
|
||||
private float mScore;
|
||||
private Bundle mExtraInfos;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param title the title to the search result.
|
||||
* @param title the title to the search result.
|
||||
* @param extraInfos the extra infos associated with the search result.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public Builder(@NonNull String title, @NonNull Bundle extraInfos) {
|
||||
mTitle = title;
|
||||
mExtraInfos = extraInfos;
|
||||
|
||||
mSnippet = "";
|
||||
mScore = 0;
|
||||
}
|
||||
|
||||
/** Sets the title to the search result. */
|
||||
@NonNull
|
||||
public Builder setTitle(@NonNull String title) {
|
||||
this.mTitle = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the snippet to the search result. */
|
||||
@NonNull
|
||||
public Builder setSnippet(@NonNull String snippet) {
|
||||
this.mSnippet = snippet;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the ranking score to the search result. */
|
||||
@NonNull
|
||||
public Builder setScore(float score) {
|
||||
this.mScore = score;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Adds extra information to the search result for rendering in the UI. */
|
||||
@NonNull
|
||||
public Builder setExtraInfos(@NonNull Bundle extraInfos) {
|
||||
this.mExtraInfos = extraInfos;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Builds a SearchResult based-on the given parameters. */
|
||||
@NonNull
|
||||
public SearchResult build() {
|
||||
if (mTitle == null || mExtraInfos == null || mSnippet == null) {
|
||||
throw new IllegalStateException("Please make sure all required args are assigned.");
|
||||
}
|
||||
|
||||
return new SearchResult(mTitle, mSnippet, mScore, mExtraInfos);
|
||||
return new SearchResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,25 +15,14 @@
|
||||
*/
|
||||
package android.service.cloudsearch;
|
||||
|
||||
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
|
||||
|
||||
import android.annotation.CallSuper;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
import android.app.Service;
|
||||
import android.app.cloudsearch.ICloudSearchManager;
|
||||
import android.app.cloudsearch.SearchRequest;
|
||||
import android.app.cloudsearch.SearchResponse;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.service.cloudsearch.ICloudSearchService.Stub;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
|
||||
/**
|
||||
* A service for returning search results from cloud services in response to an on device query.
|
||||
@@ -72,39 +61,18 @@ public abstract class CloudSearchService extends Service {
|
||||
*/
|
||||
public static final String SERVICE_INTERFACE =
|
||||
"android.service.cloudsearch.CloudSearchService";
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String TAG = "CloudSearchService";
|
||||
private Handler mHandler;
|
||||
private ICloudSearchManager mService;
|
||||
|
||||
private final android.service.cloudsearch.ICloudSearchService mInterface = new Stub() {
|
||||
@Override
|
||||
public void onSearch(SearchRequest request) {
|
||||
mHandler.sendMessage(
|
||||
obtainMessage(CloudSearchService::onSearch,
|
||||
CloudSearchService.this, request));
|
||||
}
|
||||
};
|
||||
|
||||
@CallSuper
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onCreate CloudSearchService");
|
||||
}
|
||||
mHandler = new Handler(Looper.getMainLooper(), null, true);
|
||||
|
||||
IBinder b = ServiceManager.getService(Context.CLOUDSEARCH_SERVICE);
|
||||
mService = android.app.cloudsearch.ICloudSearchManager.Stub.asInterface(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* onSearch receives the input request, retrievals the search provider's own
|
||||
* corpus and returns the search response through returnResults below.
|
||||
*
|
||||
*@param request the search request passed from the client.
|
||||
*
|
||||
* @param request the search request passed from the client.
|
||||
*/
|
||||
public abstract void onSearch(@NonNull SearchRequest request);
|
||||
|
||||
@@ -112,30 +80,16 @@ public abstract class CloudSearchService extends Service {
|
||||
* returnResults returnes the response and its associated requestId, where
|
||||
* requestIs is generated by request through getRequestId().
|
||||
*
|
||||
*@param requestId the request ID got from request.getRequestId().
|
||||
*@param response the search response returned from the search provider.
|
||||
*
|
||||
* @param requestId the request ID got from request.getRequestId().
|
||||
* @param response the search response returned from the search provider.
|
||||
*/
|
||||
public final void returnResults(@NonNull String requestId,
|
||||
@NonNull SearchResponse response) {
|
||||
try {
|
||||
mService.returnResults(mInterface.asBinder(), requestId, response);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
@NonNull SearchResponse response) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public final IBinder onBind(@NonNull Intent intent) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onBind CloudSearchService");
|
||||
}
|
||||
if (SERVICE_INTERFACE.equals(intent.getAction())) {
|
||||
return mInterface.asBinder();
|
||||
}
|
||||
Slog.w(TAG, "Tried to bind to wrong intent (should be "
|
||||
+ SERVICE_INTERFACE + ": " + intent);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.cloudsearch;
|
||||
|
||||
import android.app.cloudsearch.SearchRequest;
|
||||
|
||||
/**
|
||||
* Interface from the system to CloudSearch service.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
oneway interface ICloudSearchService {
|
||||
void onSearch(in SearchRequest request);
|
||||
}
|
||||
@@ -89,7 +89,6 @@ filegroup {
|
||||
":services.autofill-sources",
|
||||
":services.backup-sources",
|
||||
":backuplib-sources",
|
||||
":services.cloudsearch-sources",
|
||||
":services.companion-sources",
|
||||
":services.contentcapture-sources",
|
||||
":services.contentsuggestions-sources",
|
||||
@@ -144,7 +143,6 @@ java_library {
|
||||
"services.appwidget",
|
||||
"services.autofill",
|
||||
"services.backup",
|
||||
"services.cloudsearch",
|
||||
"services.companion",
|
||||
"services.contentcapture",
|
||||
"services.contentsuggestions",
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
package {
|
||||
// See: http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// all of the 'license_kinds' from "frameworks_base_license"
|
||||
// to get the below license kinds:
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["frameworks_base_license"],
|
||||
}
|
||||
|
||||
filegroup {
|
||||
name: "services.cloudsearch-sources",
|
||||
srcs: ["java/**/*.java"],
|
||||
path: "java",
|
||||
visibility: ["//frameworks/base/services"],
|
||||
}
|
||||
|
||||
java_library_static {
|
||||
name: "services.cloudsearch",
|
||||
defaults: ["platform_service_defaults"],
|
||||
srcs: [":services.cloudsearch-sources"],
|
||||
libs: ["services.core"],
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 com.android.server.cloudsearch;
|
||||
|
||||
import static android.Manifest.permission.MANAGE_CLOUDSEARCH;
|
||||
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
|
||||
import static android.content.Context.CLOUDSEARCH_SERVICE;
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.app.cloudsearch.ICloudSearchManager;
|
||||
import android.app.cloudsearch.ICloudSearchManagerCallback;
|
||||
import android.app.cloudsearch.SearchRequest;
|
||||
import android.app.cloudsearch.SearchResponse;
|
||||
import android.content.Context;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.ResultReceiver;
|
||||
import android.os.ShellCallback;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.infra.AbstractMasterSystemService;
|
||||
import com.android.server.infra.FrameworkResourcesServiceNameResolver;
|
||||
import com.android.server.wm.ActivityTaskManagerInternal;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A service used to return cloudsearch targets given a query.
|
||||
*/
|
||||
public class CloudSearchManagerService extends
|
||||
AbstractMasterSystemService<CloudSearchManagerService, CloudSearchPerUserService> {
|
||||
|
||||
private static final String TAG = CloudSearchManagerService.class.getSimpleName();
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final int MAX_TEMP_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
|
||||
|
||||
private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
public CloudSearchManagerService(Context context) {
|
||||
super(context, new FrameworkResourcesServiceNameResolver(context,
|
||||
R.array.config_defaultCloudSearchServices, true), null,
|
||||
PACKAGE_UPDATE_POLICY_NO_REFRESH | PACKAGE_RESTART_POLICY_NO_REFRESH);
|
||||
mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CloudSearchPerUserService newServiceLocked(int resolvedUserId, boolean disabled) {
|
||||
return new CloudSearchPerUserService(this, mLock, resolvedUserId, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<CloudSearchPerUserService> newServiceListLocked(int resolvedUserId,
|
||||
boolean disabled, String[] serviceNames) {
|
||||
if (serviceNames == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
List<CloudSearchPerUserService> serviceList =
|
||||
new ArrayList<>(serviceNames.length);
|
||||
for (int i = 0; i < serviceNames.length; i++) {
|
||||
if (serviceNames[i] == null) {
|
||||
continue;
|
||||
}
|
||||
serviceList.add(new CloudSearchPerUserService(this, mLock, resolvedUserId,
|
||||
serviceNames[i]));
|
||||
}
|
||||
return serviceList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
publishBinderService(CLOUDSEARCH_SERVICE, new CloudSearchManagerStub());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void enforceCallingPermissionForManagement() {
|
||||
getContext().enforceCallingPermission(MANAGE_CLOUDSEARCH, TAG);
|
||||
}
|
||||
|
||||
@Override // from AbstractMasterSystemService
|
||||
protected void onServicePackageUpdatedLocked(@UserIdInt int userId) {
|
||||
final CloudSearchPerUserService service = peekServiceForUserLocked(userId);
|
||||
if (service != null) {
|
||||
service.onPackageUpdatedLocked();
|
||||
}
|
||||
}
|
||||
|
||||
@Override // from AbstractMasterSystemService
|
||||
protected void onServicePackageRestartedLocked(@UserIdInt int userId) {
|
||||
final CloudSearchPerUserService service = peekServiceForUserLocked(userId);
|
||||
if (service != null) {
|
||||
service.onPackageRestartedLocked();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMaximumTemporaryServiceDurationMs() {
|
||||
return MAX_TEMP_SERVICE_DURATION_MS;
|
||||
}
|
||||
|
||||
private class CloudSearchManagerStub extends ICloudSearchManager.Stub {
|
||||
|
||||
@Override
|
||||
public void search(@NonNull SearchRequest searchRequest,
|
||||
@NonNull ICloudSearchManagerCallback callBack) {
|
||||
searchRequest.setCallerPackageName(
|
||||
mContext.getPackageManager().getNameForUid(Binder.getCallingUid()));
|
||||
runForUser("search", (service) -> {
|
||||
synchronized (service.mLock) {
|
||||
service.onSearchLocked(searchRequest, callBack);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnResults(IBinder token, String requestId, SearchResponse response) {
|
||||
runForUser("returnResults", (service) -> {
|
||||
synchronized (service.mLock) {
|
||||
service.onReturnResultsLocked(token, requestId, response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void destroy(@NonNull SearchRequest searchRequest) {
|
||||
runForUser("destroyCloudSearchSession", (service) -> {
|
||||
synchronized (service.mLock) {
|
||||
service.onDestroyLocked(searchRequest.getRequestId());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
|
||||
@Nullable FileDescriptor err,
|
||||
@NonNull String[] args, @Nullable ShellCallback callback,
|
||||
@NonNull ResultReceiver resultReceiver) {
|
||||
new CloudSearchManagerServiceShellCommand(CloudSearchManagerService.this)
|
||||
.exec(this, in, out, err, args, callback, resultReceiver);
|
||||
}
|
||||
|
||||
private void runForUser(@NonNull final String func,
|
||||
@NonNull final Consumer<CloudSearchPerUserService> c) {
|
||||
ActivityManagerInternal am = LocalServices.getService(ActivityManagerInternal.class);
|
||||
final int userId = am.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
|
||||
Binder.getCallingUserHandle().getIdentifier(), false, ALLOW_NON_FULL,
|
||||
null, null);
|
||||
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "runForUser:" + func + " from pid=" + Binder.getCallingPid()
|
||||
+ ", uid=" + Binder.getCallingUid());
|
||||
}
|
||||
Context ctx = getContext();
|
||||
if (!(ctx.checkCallingPermission(MANAGE_CLOUDSEARCH) == PERMISSION_GRANTED
|
||||
|| mServiceNameResolver.isTemporary(userId)
|
||||
|| mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid()))) {
|
||||
|
||||
String msg = "Permission Denial: Cannot call " + func + " from pid="
|
||||
+ Binder.getCallingPid() + ", uid=" + Binder.getCallingUid();
|
||||
Slog.w(TAG, msg);
|
||||
throw new SecurityException(msg);
|
||||
}
|
||||
|
||||
final long origId = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
final List<CloudSearchPerUserService> services =
|
||||
getServiceListForUserLocked(userId);
|
||||
for (int i = 0; i < services.size(); i++) {
|
||||
c.accept(services.get(i));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(origId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 com.android.server.cloudsearch;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.ShellCommand;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* The shell command implementation for the CloudSearchManagerService.
|
||||
*/
|
||||
public class CloudSearchManagerServiceShellCommand extends ShellCommand {
|
||||
|
||||
private static final String TAG =
|
||||
CloudSearchManagerServiceShellCommand.class.getSimpleName();
|
||||
|
||||
private final CloudSearchManagerService mService;
|
||||
|
||||
public CloudSearchManagerServiceShellCommand(@NonNull CloudSearchManagerService service) {
|
||||
mService = service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onCommand(String cmd) {
|
||||
if (cmd == null) {
|
||||
return handleDefaultCommands(cmd);
|
||||
}
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
switch (cmd) {
|
||||
case "set": {
|
||||
final String what = getNextArgRequired();
|
||||
switch (what) {
|
||||
case "temporary-service": {
|
||||
final int userId = Integer.parseInt(getNextArgRequired());
|
||||
String serviceName = getNextArg();
|
||||
if (serviceName == null) {
|
||||
mService.resetTemporaryService(userId);
|
||||
pw.println("CloudSearchService temporarily reset. ");
|
||||
return 0;
|
||||
}
|
||||
final int duration = Integer.parseInt(getNextArgRequired());
|
||||
String[] services = serviceName.split(";");
|
||||
if (services.length == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
mService.setTemporaryServices(userId, services, duration);
|
||||
}
|
||||
pw.println("CloudSearchService temporarily set to " + serviceName
|
||||
+ " for " + duration + "ms");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return handleDefaultCommands(cmd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHelp() {
|
||||
try (PrintWriter pw = getOutPrintWriter()) {
|
||||
pw.println("CloudSearchManagerService commands:");
|
||||
pw.println(" help");
|
||||
pw.println(" Prints this help text.");
|
||||
pw.println("");
|
||||
pw.println(" set temporary-service USER_ID [COMPONENT_NAME DURATION]");
|
||||
pw.println(" Temporarily (for DURATION ms) changes the service implemtation.");
|
||||
pw.println(" To reset, call with just the USER_ID argument.");
|
||||
pw.println("");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,401 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 com.android.server.cloudsearch;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.AppGlobals;
|
||||
import android.app.cloudsearch.ICloudSearchManagerCallback;
|
||||
import android.app.cloudsearch.SearchRequest;
|
||||
import android.app.cloudsearch.SearchResponse;
|
||||
import android.content.ComponentName;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.service.cloudsearch.CloudSearchService;
|
||||
import android.service.cloudsearch.ICloudSearchService;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.infra.AbstractRemoteService;
|
||||
import com.android.server.CircularQueue;
|
||||
import com.android.server.infra.AbstractPerUserSystemService;
|
||||
|
||||
/**
|
||||
* Per-user instance of {@link CloudSearchManagerService}.
|
||||
*/
|
||||
public class CloudSearchPerUserService extends
|
||||
AbstractPerUserSystemService<CloudSearchPerUserService, CloudSearchManagerService>
|
||||
implements RemoteCloudSearchService.RemoteCloudSearchServiceCallbacks {
|
||||
|
||||
private static final String TAG = CloudSearchPerUserService.class.getSimpleName();
|
||||
private static final int QUEUE_SIZE = 10;
|
||||
@GuardedBy("mLock")
|
||||
private final CircularQueue<String, CloudSearchCallbackInfo> mCallbackQueue =
|
||||
new CircularQueue<>(QUEUE_SIZE);
|
||||
private final String mServiceName;
|
||||
private final ComponentName mRemoteComponentName;
|
||||
@Nullable
|
||||
@GuardedBy("mLock")
|
||||
private RemoteCloudSearchService mRemoteService;
|
||||
/**
|
||||
* When {@code true}, remote service died but service state is kept so it's restored after
|
||||
* the system re-binds to it.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
private boolean mZombie;
|
||||
|
||||
protected CloudSearchPerUserService(CloudSearchManagerService master,
|
||||
Object lock, int userId, String serviceName) {
|
||||
super(master, lock, userId);
|
||||
mServiceName = serviceName;
|
||||
mRemoteComponentName = ComponentName.unflattenFromString(mServiceName);
|
||||
}
|
||||
|
||||
@Override // from PerUserSystemService
|
||||
protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
|
||||
throws NameNotFoundException {
|
||||
|
||||
ServiceInfo si;
|
||||
try {
|
||||
si = AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
|
||||
PackageManager.GET_META_DATA, mUserId);
|
||||
} catch (RemoteException e) {
|
||||
throw new NameNotFoundException("Could not get service for " + serviceComponent);
|
||||
}
|
||||
// TODO(b/177858728): must check that either the service is from a system component,
|
||||
// or it matches a service set by shell cmd (so it can be used on CTS tests and when
|
||||
// OEMs are implementing the real service and also verify the proper permissions
|
||||
return si;
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@Override // from PerUserSystemService
|
||||
protected boolean updateLocked(boolean disabled) {
|
||||
final boolean enabledChanged = super.updateLocked(disabled);
|
||||
if (enabledChanged) {
|
||||
if (isEnabledLocked()) {
|
||||
// Send the pending sessions over to the service
|
||||
resurrectSessionsLocked();
|
||||
} else {
|
||||
// Clear the remote service for the next call
|
||||
updateRemoteServiceLocked();
|
||||
}
|
||||
}
|
||||
return enabledChanged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the service of a new cloudsearch session.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
public void onSearchLocked(@NonNull SearchRequest searchRequest,
|
||||
@NonNull ICloudSearchManagerCallback callback) {
|
||||
if (mRemoteComponentName == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String filterList = searchRequest.getSearchConstraints().containsKey(
|
||||
SearchRequest.CONSTRAINT_SEARCH_PROVIDER_FILTER)
|
||||
? searchRequest.getSearchConstraints().getString(
|
||||
SearchRequest.CONSTRAINT_SEARCH_PROVIDER_FILTER) : "";
|
||||
|
||||
String remoteServicePackageName = mRemoteComponentName.getPackageName();
|
||||
// By default, all providers are marked as wanted.
|
||||
boolean wantedProvider = true;
|
||||
if (filterList.length() > 0) {
|
||||
// If providers are specified by the client,
|
||||
wantedProvider = false;
|
||||
String[] providersSpecified = filterList.split(";");
|
||||
for (int i = 0; i < providersSpecified.length; i++) {
|
||||
if (providersSpecified[i].equals(remoteServicePackageName)) {
|
||||
wantedProvider = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the provider was not requested by the Client, the request will not be sent to the
|
||||
// provider.
|
||||
if (!wantedProvider) {
|
||||
// TODO(216520546) Send a failure callback to the client.
|
||||
return;
|
||||
}
|
||||
final boolean serviceExists = resolveService(searchRequest,
|
||||
s -> s.onSearch(searchRequest));
|
||||
String requestId = searchRequest.getRequestId();
|
||||
if (serviceExists && !mCallbackQueue.containsKey(requestId)) {
|
||||
final CloudSearchCallbackInfo sessionInfo = new CloudSearchCallbackInfo(
|
||||
requestId, searchRequest, callback, callback.asBinder(), () -> {
|
||||
synchronized (mLock) {
|
||||
onDestroyLocked(requestId);
|
||||
}
|
||||
});
|
||||
if (sessionInfo.linkToDeath()) {
|
||||
CloudSearchCallbackInfo removedInfo = mCallbackQueue.put(requestId, sessionInfo);
|
||||
if (removedInfo != null) {
|
||||
removedInfo.destroy();
|
||||
}
|
||||
} else {
|
||||
// destroy the session if calling process is already dead
|
||||
onDestroyLocked(requestId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to return results back to the clients.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
public void onReturnResultsLocked(@NonNull IBinder token,
|
||||
@NonNull String requestId,
|
||||
@NonNull SearchResponse response) {
|
||||
if (mRemoteService == null) {
|
||||
return;
|
||||
}
|
||||
ICloudSearchService serviceInterface = mRemoteService.getServiceInterface();
|
||||
if (serviceInterface == null || token != serviceInterface.asBinder()) {
|
||||
return;
|
||||
}
|
||||
if (mCallbackQueue.containsKey(requestId)) {
|
||||
response.setSource(mServiceName);
|
||||
final CloudSearchCallbackInfo sessionInfo = mCallbackQueue.getElement(requestId);
|
||||
try {
|
||||
if (response.getStatusCode() == SearchResponse.SEARCH_STATUS_OK) {
|
||||
sessionInfo.mCallback.onSearchSucceeded(response);
|
||||
} else {
|
||||
sessionInfo.mCallback.onSearchFailed(response);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
if (mMaster.debug) {
|
||||
Slog.e(TAG, "Exception in posting results");
|
||||
e.printStackTrace();
|
||||
}
|
||||
onDestroyLocked(requestId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the server about the end of an existing cloudsearch session.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
public void onDestroyLocked(@NonNull String requestId) {
|
||||
if (isDebug()) {
|
||||
Slog.d(TAG, "onDestroyLocked(): requestId=" + requestId);
|
||||
}
|
||||
final CloudSearchCallbackInfo sessionInfo = mCallbackQueue.removeElement(requestId);
|
||||
if (sessionInfo != null) {
|
||||
sessionInfo.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailureOrTimeout(boolean timedOut) {
|
||||
if (isDebug()) {
|
||||
Slog.d(TAG, "onFailureOrTimeout(): timed out=" + timedOut);
|
||||
}
|
||||
// Do nothing, we are just proxying to the cloudsearch service
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectedStateChanged(boolean connected) {
|
||||
if (isDebug()) {
|
||||
Slog.d(TAG, "onConnectedStateChanged(): connected=" + connected);
|
||||
}
|
||||
if (connected) {
|
||||
synchronized (mLock) {
|
||||
if (mZombie) {
|
||||
// Validation check - shouldn't happen
|
||||
if (mRemoteService == null) {
|
||||
Slog.w(TAG, "Cannot resurrect sessions because remote service is null");
|
||||
return;
|
||||
}
|
||||
mZombie = false;
|
||||
resurrectSessionsLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDied(RemoteCloudSearchService service) {
|
||||
if (isDebug()) {
|
||||
Slog.w(TAG, "onServiceDied(): service=" + service);
|
||||
}
|
||||
synchronized (mLock) {
|
||||
mZombie = true;
|
||||
}
|
||||
updateRemoteServiceLocked();
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void updateRemoteServiceLocked() {
|
||||
if (mRemoteService != null) {
|
||||
mRemoteService.destroy();
|
||||
mRemoteService = null;
|
||||
}
|
||||
}
|
||||
|
||||
void onPackageUpdatedLocked() {
|
||||
if (isDebug()) {
|
||||
Slog.v(TAG, "onPackageUpdatedLocked()");
|
||||
}
|
||||
destroyAndRebindRemoteService();
|
||||
}
|
||||
|
||||
void onPackageRestartedLocked() {
|
||||
if (isDebug()) {
|
||||
Slog.v(TAG, "onPackageRestartedLocked()");
|
||||
}
|
||||
destroyAndRebindRemoteService();
|
||||
}
|
||||
|
||||
private void destroyAndRebindRemoteService() {
|
||||
if (mRemoteService == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDebug()) {
|
||||
Slog.d(TAG, "Destroying the old remote service.");
|
||||
}
|
||||
mRemoteService.destroy();
|
||||
mRemoteService = null;
|
||||
|
||||
synchronized (mLock) {
|
||||
mZombie = true;
|
||||
}
|
||||
mRemoteService = getRemoteServiceLocked();
|
||||
if (mRemoteService != null) {
|
||||
if (isDebug()) {
|
||||
Slog.d(TAG, "Rebinding to the new remote service.");
|
||||
}
|
||||
mRemoteService.reconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after the remote service connected, it's used to restore state from a 'zombie'
|
||||
* service (i.e., after it died).
|
||||
*/
|
||||
private void resurrectSessionsLocked() {
|
||||
final int numCallbacks = mCallbackQueue.size();
|
||||
if (isDebug()) {
|
||||
Slog.d(TAG, "Resurrecting remote service (" + mRemoteService + ") on "
|
||||
+ numCallbacks + " requests.");
|
||||
}
|
||||
|
||||
for (CloudSearchCallbackInfo callbackInfo : mCallbackQueue.values()) {
|
||||
callbackInfo.resurrectSessionLocked(this, callbackInfo.mToken);
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@Nullable
|
||||
protected boolean resolveService(
|
||||
@NonNull final SearchRequest requestId,
|
||||
@NonNull final AbstractRemoteService.AsyncRequest<ICloudSearchService> cb) {
|
||||
|
||||
final RemoteCloudSearchService service = getRemoteServiceLocked();
|
||||
if (service != null) {
|
||||
service.executeOnResolvedService(cb);
|
||||
}
|
||||
return service != null;
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@Nullable
|
||||
private RemoteCloudSearchService getRemoteServiceLocked() {
|
||||
if (mRemoteService == null) {
|
||||
final String serviceName = getComponentNameForMultipleLocked(mServiceName);
|
||||
if (serviceName == null) {
|
||||
if (mMaster.verbose) {
|
||||
Slog.v(TAG, "getRemoteServiceLocked(): not set");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
|
||||
|
||||
mRemoteService = new RemoteCloudSearchService(getContext(),
|
||||
CloudSearchService.SERVICE_INTERFACE, serviceComponent, mUserId, this,
|
||||
mMaster.isBindInstantServiceAllowed(), mMaster.verbose);
|
||||
}
|
||||
|
||||
return mRemoteService;
|
||||
}
|
||||
|
||||
private static final class CloudSearchCallbackInfo {
|
||||
private static final boolean DEBUG = false; // Do not submit with true
|
||||
@NonNull
|
||||
final IBinder mToken;
|
||||
@NonNull
|
||||
final IBinder.DeathRecipient mDeathRecipient;
|
||||
@NonNull
|
||||
private final String mRequestId;
|
||||
@NonNull
|
||||
private final SearchRequest mSearchRequest;
|
||||
private final ICloudSearchManagerCallback mCallback;
|
||||
|
||||
CloudSearchCallbackInfo(
|
||||
@NonNull final String id,
|
||||
@NonNull final SearchRequest request,
|
||||
@NonNull final ICloudSearchManagerCallback callback,
|
||||
@NonNull final IBinder token,
|
||||
@NonNull final IBinder.DeathRecipient deathRecipient) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Creating CloudSearchSessionInfo for session Id=" + id);
|
||||
}
|
||||
mRequestId = id;
|
||||
mSearchRequest = request;
|
||||
mCallback = callback;
|
||||
mToken = token;
|
||||
mDeathRecipient = deathRecipient;
|
||||
}
|
||||
|
||||
boolean linkToDeath() {
|
||||
try {
|
||||
mToken.linkToDeath(mDeathRecipient, 0);
|
||||
} catch (RemoteException e) {
|
||||
if (DEBUG) {
|
||||
Slog.w(TAG, "Caller is dead before session can be started, requestId: "
|
||||
+ mRequestId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Removing callback for Request Id=" + mRequestId);
|
||||
}
|
||||
if (mToken != null) {
|
||||
mToken.unlinkToDeath(mDeathRecipient, 0);
|
||||
}
|
||||
mCallback.asBinder().unlinkToDeath(mDeathRecipient, 0);
|
||||
}
|
||||
|
||||
void resurrectSessionLocked(CloudSearchPerUserService service, IBinder token) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Resurrecting remote service (" + service.getRemoteServiceLocked()
|
||||
+ ") for request Id=" + mRequestId);
|
||||
}
|
||||
service.onSearchLocked(mSearchRequest, mCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 com.android.server.cloudsearch;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.os.IBinder;
|
||||
import android.service.cloudsearch.ICloudSearchService;
|
||||
import android.text.format.DateUtils;
|
||||
|
||||
import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
|
||||
|
||||
|
||||
/**
|
||||
* Proxy to the {@link android.service.cloudsearch.CloudSearchService} implementation in another
|
||||
* process.
|
||||
*/
|
||||
public class RemoteCloudSearchService extends
|
||||
AbstractMultiplePendingRequestsRemoteService<RemoteCloudSearchService,
|
||||
ICloudSearchService> {
|
||||
|
||||
private static final String TAG = "RemoteCloudSearchService";
|
||||
|
||||
private static final long TIMEOUT_IDLE_BOUND_TIMEOUT_MS = 10 * DateUtils.MINUTE_IN_MILLIS;
|
||||
private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.SECOND_IN_MILLIS;
|
||||
|
||||
private final RemoteCloudSearchServiceCallbacks mCallback;
|
||||
|
||||
public RemoteCloudSearchService(Context context, String serviceInterface,
|
||||
ComponentName componentName, int userId,
|
||||
RemoteCloudSearchServiceCallbacks callback, boolean bindInstantServiceAllowed,
|
||||
boolean verbose) {
|
||||
super(context, serviceInterface, componentName, userId, callback,
|
||||
context.getMainThreadHandler(),
|
||||
bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0,
|
||||
verbose, /* initialCapacity= */ 1);
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ICloudSearchService getServiceInterface(IBinder service) {
|
||||
return ICloudSearchService.Stub.asInterface(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getTimeoutIdleBindMillis() {
|
||||
return TIMEOUT_IDLE_BOUND_TIMEOUT_MS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getRemoteRequestMillis() {
|
||||
return TIMEOUT_REMOTE_REQUEST_MILLIS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules a request to bind to the remote service.
|
||||
*/
|
||||
public void reconnect() {
|
||||
super.scheduleBind();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule async request on remote service.
|
||||
*/
|
||||
public void scheduleOnResolvedService(@NonNull AsyncRequest<ICloudSearchService> request) {
|
||||
scheduleAsyncRequest(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute async request on remote service immediately instead of sending it to Handler queue.
|
||||
*/
|
||||
public void executeOnResolvedService(@NonNull AsyncRequest<ICloudSearchService> request) {
|
||||
executeAsyncRequest(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Failure callback
|
||||
*/
|
||||
public interface RemoteCloudSearchServiceCallbacks
|
||||
extends VultureCallback<RemoteCloudSearchService> {
|
||||
|
||||
/**
|
||||
* Notifies a the failure or timeout of a remote call.
|
||||
*/
|
||||
void onFailureOrTimeout(boolean timedOut);
|
||||
|
||||
/**
|
||||
* Notifies change in connected state of the remote service.
|
||||
*/
|
||||
void onConnectedStateChanged(boolean connected);
|
||||
}
|
||||
|
||||
@Override // from AbstractRemoteService
|
||||
protected void handleOnConnectedStateChanged(boolean connected) {
|
||||
if (mCallback != null) {
|
||||
mCallback.onConnectedStateChanged(connected);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -378,8 +378,6 @@ public final class SystemServer implements Dumpable {
|
||||
"com.android.server.searchui.SearchUiManagerService";
|
||||
private static final String SMARTSPACE_MANAGER_SERVICE_CLASS =
|
||||
"com.android.server.smartspace.SmartspaceManagerService";
|
||||
private static final String CLOUDSEARCH_MANAGER_SERVICE_CLASS =
|
||||
"com.android.server.cloudsearch.CloudSearchManagerService";
|
||||
private static final String DEVICE_IDLE_CONTROLLER_CLASS =
|
||||
"com.android.server.DeviceIdleController";
|
||||
private static final String BLOB_STORE_MANAGER_SERVICE_CLASS =
|
||||
@@ -1886,12 +1884,6 @@ public final class SystemServer implements Dumpable {
|
||||
mSystemServiceManager.startService(SMARTSPACE_MANAGER_SERVICE_CLASS);
|
||||
t.traceEnd();
|
||||
|
||||
// CloudSearch manager service
|
||||
// TODO: add deviceHasConfigString(context, R.string.config_defaultCloudSearchServices)
|
||||
t.traceBegin("StartCloudSearchService");
|
||||
mSystemServiceManager.startService(CLOUDSEARCH_MANAGER_SERVICE_CLASS);
|
||||
t.traceEnd();
|
||||
|
||||
t.traceBegin("InitConnectivityModuleConnector");
|
||||
try {
|
||||
ConnectivityModuleConnector.getInstance().init(context);
|
||||
|
||||
Reference in New Issue
Block a user