1 /* 2 * Copyright 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.appsearch.external.localstorage.stats; 18 19 import android.annotation.NonNull; 20 import android.app.appsearch.annotation.CanIgnoreReturnValue; 21 22 import java.util.Objects; 23 24 // TODO(b/319285816): link converter here. 25 /** 26 * Class holds detailed stats of a click action, converted from {@link 27 * android.app.appsearch.PutDocumentsRequest#getTakenActionGenericDocuments}. 28 * 29 * @hide 30 */ 31 public class ClickStats { 32 private final long mTimestampMillis; 33 34 private final long mTimeStayOnResultMillis; 35 36 private final int mResultRankInBlock; 37 38 private final int mResultRankGlobal; 39 40 private final boolean mIsGoodClick; 41 ClickStats(@onNull Builder builder)42 ClickStats(@NonNull Builder builder) { 43 Objects.requireNonNull(builder); 44 mTimestampMillis = builder.mTimestampMillis; 45 mTimeStayOnResultMillis = builder.mTimeStayOnResultMillis; 46 mResultRankInBlock = builder.mResultRankInBlock; 47 mResultRankGlobal = builder.mResultRankGlobal; 48 mIsGoodClick = builder.mIsGoodClick; 49 } 50 51 /** Returns the click action timestamp in milliseconds since Unix epoch. */ getTimestampMillis()52 public long getTimestampMillis() { 53 return mTimestampMillis; 54 } 55 56 /** Returns the time (duration) of the user staying on the clicked result. */ getTimeStayOnResultMillis()57 public long getTimeStayOnResultMillis() { 58 return mTimeStayOnResultMillis; 59 } 60 61 /** Returns the in-block rank of the clicked result. */ getResultRankInBlock()62 public int getResultRankInBlock() { 63 return mResultRankInBlock; 64 } 65 66 /** Returns the global rank of the clicked result. */ getResultRankGlobal()67 public int getResultRankGlobal() { 68 return mResultRankGlobal; 69 } 70 71 /** 72 * Returns whether this click is a good click or not. 73 * 74 * @see Builder#setIsGoodClick 75 */ isGoodClick()76 public boolean isGoodClick() { 77 return mIsGoodClick; 78 } 79 80 /** Builder for {@link ClickStats} */ 81 public static final class Builder { 82 private long mTimestampMillis; 83 84 private long mTimeStayOnResultMillis; 85 86 private int mResultRankInBlock; 87 88 private int mResultRankGlobal; 89 90 private boolean mIsGoodClick = true; 91 92 /** Sets the click action timestamp in milliseconds since Unix epoch. */ 93 @CanIgnoreReturnValue 94 @NonNull setTimestampMillis(long timestampMillis)95 public Builder setTimestampMillis(long timestampMillis) { 96 mTimestampMillis = timestampMillis; 97 return this; 98 } 99 100 /** Sets the time (duration) of the user staying on the clicked result. */ 101 @CanIgnoreReturnValue 102 @NonNull setTimeStayOnResultMillis(long timeStayOnResultMillis)103 public Builder setTimeStayOnResultMillis(long timeStayOnResultMillis) { 104 mTimeStayOnResultMillis = timeStayOnResultMillis; 105 return this; 106 } 107 108 /** Sets the in-block rank of the clicked result. */ 109 @CanIgnoreReturnValue 110 @NonNull setResultRankInBlock(int resultRankInBlock)111 public Builder setResultRankInBlock(int resultRankInBlock) { 112 mResultRankInBlock = resultRankInBlock; 113 return this; 114 } 115 116 /** Sets the global rank of the clicked result. */ 117 @CanIgnoreReturnValue 118 @NonNull setResultRankGlobal(int resultRankGlobal)119 public Builder setResultRankGlobal(int resultRankGlobal) { 120 mResultRankGlobal = resultRankGlobal; 121 return this; 122 } 123 124 /** 125 * Sets the flag indicating whether the click is good or not. 126 * 127 * <p>A good click means the user is satisfied by the clicked document. The caller should 128 * define its own criteria and set this field accordingly. 129 * 130 * <p>The default value is true if unset. We should treat it as a good click by default if 131 * the caller didn't specify or could not determine for several reasons: 132 * 133 * <ul> 134 * <li>It may be difficult for the caller to determine if the user is satisfied by the 135 * clicked document or not. 136 * <li>AppSearch collects search quality metrics that are related to number of good 137 * clicks. We don't want to demote the quality score aggressively by the undetermined 138 * ones. 139 * </ul> 140 */ 141 @CanIgnoreReturnValue 142 @NonNull setIsGoodClick(boolean isGoodClick)143 public Builder setIsGoodClick(boolean isGoodClick) { 144 mIsGoodClick = isGoodClick; 145 return this; 146 } 147 148 /** Builds a new {@link ClickStats} from the {@link ClickStats.Builder}. */ 149 @NonNull build()150 public ClickStats build() { 151 return new ClickStats(/* builder= */ this); 152 } 153 } 154 } 155