Merge "CloudSearch API: add the field of source to SearchRequest"
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 5e5f387..179c508 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1647,6 +1647,7 @@
     method public int getResultNumber();
     method public int getResultOffset();
     method @NonNull public android.os.Bundle getSearchConstraints();
+    method @NonNull public String getSource();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final String CONSTRAINT_IS_PRESUBMIT_SUGGESTION = "IS_PRESUBMIT_SUGGESTION";
     field public static final String CONSTRAINT_SEARCH_PROVIDER_FILTER = "SEARCH_PROVIDER_FILTER";
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index bcba21b0..9634252 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -605,6 +605,14 @@
 
 }
 
+package android.app.cloudsearch {
+
+  public static final class SearchRequest.Builder {
+    method @NonNull public android.app.cloudsearch.SearchRequest.Builder setSource(@NonNull String);
+  }
+
+}
+
 package android.app.contentsuggestions {
 
   public final class ContentSuggestionsManager {
diff --git a/core/java/android/app/cloudsearch/SearchRequest.java b/core/java/android/app/cloudsearch/SearchRequest.java
index 0c5c30c..ef66c0c 100644
--- a/core/java/android/app/cloudsearch/SearchRequest.java
+++ b/core/java/android/app/cloudsearch/SearchRequest.java
@@ -21,6 +21,7 @@
 import android.annotation.Nullable;
 import android.annotation.StringDef;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -91,6 +92,14 @@
     @NonNull
     private Bundle mSearchConstraints;
 
+    /** Auto set by system servier, and the caller cannot set it.
+     *
+     * The caller's package name.
+     *
+     */
+    @NonNull
+    private String mSource;
+
     private SearchRequest(Parcel in) {
         this.mQuery = in.readString();
         this.mResultOffset = in.readInt();
@@ -98,15 +107,17 @@
         this.mMaxLatencyMillis = in.readFloat();
         this.mSearchConstraints = in.readBundle();
         this.mId = in.readString();
+        this.mSource = in.readString();
     }
 
     private SearchRequest(String query, int resultOffset, int resultNumber, float maxLatencyMillis,
-            Bundle searchConstraints) {
+            Bundle searchConstraints, String source) {
         mQuery = query;
         mResultOffset = resultOffset;
         mResultNumber = resultNumber;
         mMaxLatencyMillis = maxLatencyMillis;
         mSearchConstraints = searchConstraints;
+        mSource = source;
     }
 
     /** Returns the original query. */
@@ -136,35 +147,37 @@
         return mSearchConstraints;
     }
 
+    /** Gets the caller's package name. */
+    @NonNull
+    public String getSource() {
+        return mSource;
+    }
+
     /** Returns the search request id, which is used to identify the request. */
     @NonNull
     public String getRequestId() {
         if (mId == null || mId.length() == 0) {
-            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);
-            }
-
-            String rawContent = String.format("%s\t%d\t%d\t%f\t%b\t%s",
-                    mQuery, mResultOffset, mResultNumber, mMaxLatencyMillis,
-                    isPresubmit, searchProvider);
-
-            mId = String.valueOf(rawContent.hashCode());
+            mId = String.valueOf(toString().hashCode());
         }
 
         return mId;
     }
 
+    /** Sets the caller, and this will be set by the system server.
+     *
+     * @hide
+     */
+    public void setSource(@NonNull String source) {
+        this.mSource = source;
+    }
+
     private SearchRequest(Builder b) {
         mQuery = requireNonNull(b.mQuery);
         mResultOffset = b.mResultOffset;
         mResultNumber = b.mResultNumber;
         mMaxLatencyMillis = b.mMaxLatencyMillis;
         mSearchConstraints = requireNonNull(b.mSearchConstraints);
+        mSource = requireNonNull(b.mSource);
     }
 
     /**
@@ -192,6 +205,7 @@
         dest.writeFloat(this.mMaxLatencyMillis);
         dest.writeBundle(this.mSearchConstraints);
         dest.writeString(getRequestId());
+        dest.writeString(this.mSource);
     }
 
     @Override
@@ -214,13 +228,30 @@
                 && mResultOffset == that.mResultOffset
                 && mResultNumber == that.mResultNumber
                 && mMaxLatencyMillis == that.mMaxLatencyMillis
-                && Objects.equals(mSearchConstraints, that.mSearchConstraints);
+                && Objects.equals(mSearchConstraints, that.mSearchConstraints)
+                && Objects.equals(mSource, that.mSource);
+    }
+
+    @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;source:%s}", mQuery, mResultOffset,
+                mResultNumber, mMaxLatencyMillis, isPresubmit, searchProvider, mSource);
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mQuery, mResultOffset, mResultNumber, mMaxLatencyMillis,
-                mSearchConstraints);
+                mSearchConstraints, mSource);
     }
 
     /**
@@ -235,6 +266,7 @@
         private int mResultNumber;
         private float mMaxLatencyMillis;
         private Bundle mSearchConstraints;
+        private String mSource;
 
         /**
          *
@@ -250,6 +282,7 @@
             mResultNumber = 10;
             mMaxLatencyMillis = 200;
             mSearchConstraints = Bundle.EMPTY;
+            mSource = "DEFAULT_CALLER";
         }
 
         /** Sets the input query. */
@@ -288,6 +321,17 @@
             return this;
         }
 
+        /** Sets the caller, and this will be set by the system server.
+         *
+         * @hide
+         */
+        @NonNull
+        @TestApi
+        public Builder setSource(@NonNull String source) {
+            this.mSource = source;
+            return this;
+        }
+
         /** Builds a SearchRequest based-on the given params. */
         @NonNull
         public SearchRequest build() {
@@ -297,7 +341,7 @@
             }
 
             return new SearchRequest(mQuery, mResultOffset, mResultNumber, mMaxLatencyMillis,
-                               mSearchConstraints);
+                               mSearchConstraints, mSource);
         }
     }
 }
diff --git a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java
index dafe7a4..daead0a 100644
--- a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java
+++ b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java
@@ -58,11 +58,14 @@
 
     private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
 
+    private final Context mContext;
+
     public CloudSearchManagerService(Context context) {
         super(context, new FrameworkResourcesServiceNameResolver(context,
                         R.string.config_defaultCloudSearchService), null,
                 PACKAGE_UPDATE_POLICY_NO_REFRESH | PACKAGE_RESTART_POLICY_NO_REFRESH);
         mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
+        mContext = context;
     }
 
     @Override
@@ -106,6 +109,8 @@
         @Override
         public void search(@NonNull SearchRequest searchRequest,
                 @NonNull ICloudSearchManagerCallback callBack) {
+            searchRequest.setSource(
+                    mContext.getPackageManager().getNameForUid(Binder.getCallingUid()));
             runForUserLocked("search", searchRequest.getRequestId(), (service) ->
                     service.onSearchLocked(searchRequest, callBack));
         }