1 /* 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 */ 16 package android.content; 17 18 import android.annotation.NonNull; 19 import android.annotation.Nullable; 20 import android.os.Parcel; 21 import android.os.Parcelable; 22 import android.view.contentcapture.ContentCaptureManager; 23 24 import com.android.internal.util.Preconditions; 25 26 import java.io.PrintWriter; 27 28 /** 29 * An identifier for an unique state (locus) in the application. Should be stable across reboots and 30 * backup / restore. 31 * 32 * <p>Locus is a new concept introduced on 33 * {@link android.os.Build.VERSION_CODES#Q Android Q} and it lets the intelligence service provided 34 * by the Android System to correlate state between different subsystems such as content capture, 35 * shortcuts, and notifications. 36 * 37 * <p>For example, if your app provides an activity representing a chat between 2 users 38 * (say {@code A} and {@code B}, this chat state could be represented by: 39 * 40 * <pre><code> 41 * LocusId chatId = new LocusId("Chat_A_B"); 42 * </code></pre> 43 * 44 * <p>And then you should use that {@code chatId} by: 45 * 46 * <ul> 47 * <li>Setting it in the chat notification (through 48 * {@link android.app.Notification.Builder#setLocusId(LocusId) 49 * Notification.Builder.setLocusId(chatId)}). 50 * <li>Setting it into the {@link android.content.pm.ShortcutInfo} (through 51 * {@link android.content.pm.ShortcutInfo.Builder#setLocusId(LocusId) 52 * ShortcutInfo.Builder.setLocusId(chatId)}), if you provide a launcher shortcut for that chat 53 * conversation. 54 * <li>Associating it with the {@link android.view.contentcapture.ContentCaptureContext} of the 55 * root view of the chat conversation activity (through 56 * {@link android.view.View#getContentCaptureSession()}, then 57 * {@link android.view.contentcapture.ContentCaptureContext.Builder 58 * new ContentCaptureContext.Builder(chatId).build()} and 59 * {@link android.view.contentcapture.ContentCaptureSession#setContentCaptureContext( 60 * android.view.contentcapture.ContentCaptureContext)} - see {@link ContentCaptureManager} 61 * for more info about content capture). 62 * <li>Configuring your app to launch the chat conversation through the 63 * {@link Intent#ACTION_VIEW_LOCUS} intent. 64 * </ul> 65 */ 66 public final class LocusId implements Parcelable { 67 68 private final String mId; 69 70 /** 71 * Default constructor. 72 * 73 * @throws IllegalArgumentException if {@code id} is empty or {@code null}. 74 */ LocusId(@onNull String id)75 public LocusId(@NonNull String id) { 76 mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty"); 77 } 78 79 /** 80 * Gets the canonical {@code id} associated with the locus. 81 */ 82 @NonNull getId()83 public String getId() { 84 return mId; 85 } 86 87 @Override hashCode()88 public int hashCode() { 89 final int prime = 31; 90 int result = 1; 91 result = prime * result + ((mId == null) ? 0 : mId.hashCode()); 92 return result; 93 } 94 95 @Override equals(@ullable Object obj)96 public boolean equals(@Nullable Object obj) { 97 if (this == obj) return true; 98 if (obj == null) return false; 99 if (getClass() != obj.getClass()) return false; 100 final LocusId other = (LocusId) obj; 101 if (mId == null) { 102 if (other.mId != null) return false; 103 } else { 104 if (!mId.equals(other.mId)) return false; 105 } 106 return true; 107 } 108 109 @Override toString()110 public String toString() { 111 return "LocusId[" + getSanitizedId() + "]"; 112 } 113 114 /** @hide */ dump(@onNull PrintWriter pw)115 public void dump(@NonNull PrintWriter pw) { 116 pw.print("id:"); pw.println(getSanitizedId()); 117 } 118 119 @NonNull getSanitizedId()120 private String getSanitizedId() { 121 final int size = mId.length(); 122 return size + "_chars"; 123 } 124 125 @Override describeContents()126 public int describeContents() { 127 return 0; 128 } 129 130 @Override writeToParcel(Parcel parcel, int flags)131 public void writeToParcel(Parcel parcel, int flags) { 132 parcel.writeString(mId); 133 } 134 135 public static final @NonNull Parcelable.Creator<LocusId> CREATOR = 136 new Parcelable.Creator<LocusId>() { 137 138 @NonNull 139 @Override 140 public LocusId createFromParcel(Parcel parcel) { 141 return new LocusId(parcel.readString()); 142 } 143 144 @NonNull 145 @Override 146 public LocusId[] newArray(int size) { 147 return new LocusId[size]; 148 } 149 }; 150 } 151