blob: 283cea00b1926c31453718c98060dde4201f45a1 [file] [log] [blame]
Felipe Leme044c63b2019-02-12 14:35:20 -08001/*
2 * Copyright (C) 2019 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 */
16package android.content;
17
18import android.annotation.NonNull;
Felipe Leme044c63b2019-02-12 14:35:20 -080019import android.os.Parcel;
20import android.os.Parcelable;
Felipe Lemef0d44c62019-03-26 16:36:58 -070021import android.view.contentcapture.ContentCaptureManager;
Felipe Leme044c63b2019-02-12 14:35:20 -080022
23import com.android.internal.util.Preconditions;
24
25import java.io.PrintWriter;
26
27/**
Felipe Lemef0d44c62019-03-26 16:36:58 -070028 * An identifier for an unique state (locus) in the application. Should be stable across reboots and
29 * backup / restore.
Felipe Leme044c63b2019-02-12 14:35:20 -080030 *
Felipe Lemef0d44c62019-03-26 16:36:58 -070031 * <p>Locus is a new concept introduced on
32 * {@link android.os.Build.VERSION_CODES#Q Android Q} and it lets the intelligence service provided
33 * by the Android System to correlate state between different subsystems such as content capture,
34 * shortcuts, and notifications.
Felipe Leme044c63b2019-02-12 14:35:20 -080035 *
Felipe Lemef0d44c62019-03-26 16:36:58 -070036 * <p>For example, if your app provides an activiy representing a chat between 2 users
37 * (say {@code A} and {@code B}, this chat state could be represented by:
38 *
39 * <pre><code>
40 * LocusId chatId = new LocusId("Chat_A_B");
41 * </code></pre>
42 *
43 * <p>And then you should use that {@code chatId} by:
44 *
45 * <ul>
46 * <li>Setting it in the chat notification (through
47 * {@link android.app.Notification.Builder#setLocusId(LocusId)
48 * Notification.Builder.setLocusId(chatId)}).
49 * <li>Setting it into the {@link android.content.pm.ShortcutInfo} (through
50 * {@link android.content.pm.ShortcutInfo.Builder#setLocusId(LocusId)
51 * ShortcutInfo.Builder.setLocusId(chatId)}), if you provide a launcher shortcut for that chat
52 * conversation.
53 * <li>Associating it with the {@link android.view.contentcapture.ContentCaptureContext} of the
54 * root view of the chat conversation activity (through
55 * {@link android.view.View#getContentCaptureSession()}, then
56 * {@link android.view.contentcapture.ContentCaptureContext.Builder
57 * new ContentCaptureContext.Builder(chatId).build()} and
58 * {@link android.view.contentcapture.ContentCaptureSession#setContentCaptureContext(
59 * android.view.contentcapture.ContentCaptureContext)} - see {@link ContentCaptureManager}
60 * for more info about content capture).
61 * <li>Configuring your app to launch the chat conversation through the
62 * {@link Intent#ACTION_VIEW_LOCUS} intent.
63 * </ul>
Felipe Leme044c63b2019-02-12 14:35:20 -080064 */
Felipe Leme044c63b2019-02-12 14:35:20 -080065public final class LocusId implements Parcelable {
66
Felipe Leme7e735752019-03-01 16:27:24 -080067 private final String mId;
Felipe Leme044c63b2019-02-12 14:35:20 -080068
69 /**
70 * Default constructor.
Felipe Leme85e2b012019-03-05 09:41:03 -080071 *
72 * @throws IllegalArgumentException if {@code id} is empty or {@code null}.
Felipe Leme044c63b2019-02-12 14:35:20 -080073 */
Felipe Leme7e735752019-03-01 16:27:24 -080074 public LocusId(@NonNull String id) {
Felipe Leme85e2b012019-03-05 09:41:03 -080075 mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty");
Felipe Leme044c63b2019-02-12 14:35:20 -080076 }
77
78 /**
Felipe Lemef0d44c62019-03-26 16:36:58 -070079 * Gets the canonical {@code id} associated with the locus.
Felipe Leme044c63b2019-02-12 14:35:20 -080080 */
81 @NonNull
Felipe Leme7e735752019-03-01 16:27:24 -080082 public String getId() {
83 return mId;
Felipe Leme044c63b2019-02-12 14:35:20 -080084 }
85
86 @Override
87 public int hashCode() {
88 final int prime = 31;
89 int result = 1;
Felipe Leme7e735752019-03-01 16:27:24 -080090 result = prime * result + ((mId == null) ? 0 : mId.hashCode());
Felipe Leme044c63b2019-02-12 14:35:20 -080091 return result;
92 }
93
94 @Override
95 public boolean equals(Object obj) {
96 if (this == obj) return true;
97 if (obj == null) return false;
98 if (getClass() != obj.getClass()) return false;
99 final LocusId other = (LocusId) obj;
Felipe Leme7e735752019-03-01 16:27:24 -0800100 if (mId == null) {
101 if (other.mId != null) return false;
Felipe Leme044c63b2019-02-12 14:35:20 -0800102 } else {
Felipe Leme7e735752019-03-01 16:27:24 -0800103 if (!mId.equals(other.mId)) return false;
Felipe Leme044c63b2019-02-12 14:35:20 -0800104 }
105 return true;
106 }
107
108 @Override
109 public String toString() {
Felipe Leme7e735752019-03-01 16:27:24 -0800110 return "LocusId[" + getSanitizedId() + "]";
Felipe Leme044c63b2019-02-12 14:35:20 -0800111 }
112
113 /** @hide */
114 public void dump(@NonNull PrintWriter pw) {
Felipe Leme7e735752019-03-01 16:27:24 -0800115 pw.print("id:"); pw.println(getSanitizedId());
Felipe Leme044c63b2019-02-12 14:35:20 -0800116 }
117
Felipe Leme7e735752019-03-01 16:27:24 -0800118 @NonNull
119 private String getSanitizedId() {
120 final int size = mId.length();
Felipe Leme044c63b2019-02-12 14:35:20 -0800121 return size + "_chars";
122 }
123
124 @Override
125 public int describeContents() {
126 return 0;
127 }
128
129 @Override
Felipe Leme7e735752019-03-01 16:27:24 -0800130 public void writeToParcel(Parcel parcel, int flags) {
131 parcel.writeString(mId);
Felipe Leme044c63b2019-02-12 14:35:20 -0800132 }
133
Felipe Lemef0d44c62019-03-26 16:36:58 -0700134 public static final @NonNull Parcelable.Creator<LocusId> CREATOR =
Felipe Leme044c63b2019-02-12 14:35:20 -0800135 new Parcelable.Creator<LocusId>() {
136
Felipe Lemece6877b2019-02-28 09:02:26 -0800137 @NonNull
Felipe Leme044c63b2019-02-12 14:35:20 -0800138 @Override
Felipe Leme7e735752019-03-01 16:27:24 -0800139 public LocusId createFromParcel(Parcel parcel) {
140 return new LocusId(parcel.readString());
Felipe Leme044c63b2019-02-12 14:35:20 -0800141 }
142
Felipe Lemece6877b2019-02-28 09:02:26 -0800143 @NonNull
Felipe Leme044c63b2019-02-12 14:35:20 -0800144 @Override
145 public LocusId[] newArray(int size) {
146 return new LocusId[size];
147 }
148 };
149}