1 /* 2 * Copyright (C) 2007 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 android.database; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.UserIdInt; 22 import android.app.compat.CompatChanges; 23 import android.compat.annotation.ChangeId; 24 import android.compat.annotation.EnabledAfter; 25 import android.compat.annotation.UnsupportedAppUsage; 26 import android.content.ContentResolver.NotifyFlags; 27 import android.net.Uri; 28 import android.os.Handler; 29 import android.os.UserHandle; 30 31 import java.util.Arrays; 32 import java.util.Collection; 33 34 /** 35 * Receives call backs for changes to content. 36 * Must be implemented by objects which are added to a {@link ContentObservable}. 37 */ 38 public abstract class ContentObserver { 39 /** 40 * Starting in {@link android.os.Build.VERSION_CODES#R}, there is a new 41 * public API overload {@link #onChange(boolean, Uri, int)} that delivers a 42 * {@code int flags} argument. 43 * <p> 44 * Some apps may be relying on a previous hidden API that delivered a 45 * {@code int userId} argument, and this change is used to control delivery 46 * of the new {@code int flags} argument in its place. 47 */ 48 @ChangeId 49 @EnabledAfter(targetSdkVersion=android.os.Build.VERSION_CODES.Q) 50 private static final long ADD_CONTENT_OBSERVER_FLAGS = 150939131L; 51 52 private final Object mLock = new Object(); 53 private Transport mTransport; // guarded by mLock 54 55 Handler mHandler; 56 57 /** 58 * Creates a content observer. 59 * 60 * @param handler The handler to run {@link #onChange} on, or null if none. 61 */ ContentObserver(Handler handler)62 public ContentObserver(Handler handler) { 63 mHandler = handler; 64 } 65 66 /** 67 * Gets access to the binder transport object. Not for public consumption. 68 * 69 * {@hide} 70 */ getContentObserver()71 public IContentObserver getContentObserver() { 72 synchronized (mLock) { 73 if (mTransport == null) { 74 mTransport = new Transport(this); 75 } 76 return mTransport; 77 } 78 } 79 80 /** 81 * Gets access to the binder transport object, and unlinks the transport object 82 * from the ContentObserver. Not for public consumption. 83 * 84 * {@hide} 85 */ 86 @UnsupportedAppUsage releaseContentObserver()87 public IContentObserver releaseContentObserver() { 88 synchronized (mLock) { 89 final Transport oldTransport = mTransport; 90 if (oldTransport != null) { 91 oldTransport.releaseContentObserver(); 92 mTransport = null; 93 } 94 return oldTransport; 95 } 96 } 97 98 /** 99 * Returns true if this observer is interested receiving self-change notifications. 100 * 101 * Subclasses should override this method to indicate whether the observer 102 * is interested in receiving notifications for changes that it made to the 103 * content itself. 104 * 105 * @return True if self-change notifications should be delivered to the observer. 106 */ deliverSelfNotifications()107 public boolean deliverSelfNotifications() { 108 return false; 109 } 110 111 /** 112 * This method is called when a content change occurs. 113 * <p> 114 * Subclasses should override this method to handle content changes. 115 * </p> 116 * 117 * @param selfChange True if this is a self-change notification. 118 */ onChange(boolean selfChange)119 public void onChange(boolean selfChange) { 120 // Do nothing. Subclass should override. 121 } 122 123 /** 124 * This method is called when a content change occurs. 125 * Includes the changed content Uri when available. 126 * <p> 127 * Subclasses should override this method to handle content changes. To 128 * ensure correct operation on older versions of the framework that did not 129 * provide richer arguments, applications should implement all overloads. 130 * <p> 131 * Example implementation: 132 * <pre><code> 133 * // Implement the onChange(boolean) method to delegate the change notification to 134 * // the onChange(boolean, Uri) method to ensure correct operation on older versions 135 * // of the framework that did not have the onChange(boolean, Uri) method. 136 * {@literal @Override} 137 * public void onChange(boolean selfChange) { 138 * onChange(selfChange, null); 139 * } 140 * 141 * // Implement the onChange(boolean, Uri) method to take advantage of the new Uri argument. 142 * {@literal @Override} 143 * public void onChange(boolean selfChange, Uri uri) { 144 * // Handle change. 145 * } 146 * </code></pre> 147 * </p> 148 * 149 * @param selfChange True if this is a self-change notification. 150 * @param uri The Uri of the changed content. 151 */ onChange(boolean selfChange, @Nullable Uri uri)152 public void onChange(boolean selfChange, @Nullable Uri uri) { 153 onChange(selfChange); 154 } 155 156 /** 157 * This method is called when a content change occurs. Includes the changed 158 * content Uri when available. 159 * <p> 160 * Subclasses should override this method to handle content changes. To 161 * ensure correct operation on older versions of the framework that did not 162 * provide richer arguments, applications should implement all overloads. 163 * 164 * @param selfChange True if this is a self-change notification. 165 * @param uri The Uri of the changed content. 166 * @param flags Flags indicating details about this change. 167 */ onChange(boolean selfChange, @Nullable Uri uri, @NotifyFlags int flags)168 public void onChange(boolean selfChange, @Nullable Uri uri, @NotifyFlags int flags) { 169 onChange(selfChange, uri); 170 } 171 172 /** 173 * This method is called when a content change occurs. Includes the changed 174 * content Uris when available. 175 * <p> 176 * Subclasses should override this method to handle content changes. To 177 * ensure correct operation on older versions of the framework that did not 178 * provide richer arguments, applications should implement all overloads. 179 * 180 * @param selfChange True if this is a self-change notification. 181 * @param uris The Uris of the changed content. 182 * @param flags Flags indicating details about this change. 183 */ onChange(boolean selfChange, @NonNull Collection<Uri> uris, @NotifyFlags int flags)184 public void onChange(boolean selfChange, @NonNull Collection<Uri> uris, 185 @NotifyFlags int flags) { 186 for (Uri uri : uris) { 187 onChange(selfChange, uri, flags); 188 } 189 } 190 191 /** @hide */ onChange(boolean selfChange, @NonNull Collection<Uri> uris, @NotifyFlags int flags, @UserIdInt int userId)192 public void onChange(boolean selfChange, @NonNull Collection<Uri> uris, 193 @NotifyFlags int flags, @UserIdInt int userId) { 194 // There are dozens of people relying on the hidden API inside the 195 // system UID, so hard-code the old behavior for all of them; for 196 // everyone else we gate based on a specific change 197 if (!CompatChanges.isChangeEnabled(ADD_CONTENT_OBSERVER_FLAGS) 198 || android.os.Process.myUid() == android.os.Process.SYSTEM_UID) { 199 // Deliver userId through argument to preserve hidden API behavior 200 onChange(selfChange, uris, userId); 201 } else { 202 onChange(selfChange, uris, flags); 203 } 204 } 205 206 /** 207 * Dispatches a change notification to the observer. 208 * <p> 209 * If a {@link Handler} was supplied to the {@link ContentObserver} 210 * constructor, then a call to the {@link #onChange} method is posted to the 211 * handler's message queue. Otherwise, the {@link #onChange} method is 212 * invoked immediately on this thread. 213 * 214 * @deprecated Callers should migrate towards using a richer overload that 215 * provides more details about the change, such as 216 * {@link #dispatchChange(boolean, Collection, int)}. 217 */ 218 @Deprecated dispatchChange(boolean selfChange)219 public final void dispatchChange(boolean selfChange) { 220 dispatchChange(selfChange, null); 221 } 222 223 /** 224 * Dispatches a change notification to the observer. Includes the changed 225 * content Uri when available. 226 * <p> 227 * If a {@link Handler} was supplied to the {@link ContentObserver} 228 * constructor, then a call to the {@link #onChange} method is posted to the 229 * handler's message queue. Otherwise, the {@link #onChange} method is 230 * invoked immediately on this thread. 231 * 232 * @param selfChange True if this is a self-change notification. 233 * @param uri The Uri of the changed content. 234 */ dispatchChange(boolean selfChange, @Nullable Uri uri)235 public final void dispatchChange(boolean selfChange, @Nullable Uri uri) { 236 dispatchChange(selfChange, uri, 0); 237 } 238 239 /** 240 * Dispatches a change notification to the observer. Includes the changed 241 * content Uri when available. 242 * <p> 243 * If a {@link Handler} was supplied to the {@link ContentObserver} 244 * constructor, then a call to the {@link #onChange} method is posted to the 245 * handler's message queue. Otherwise, the {@link #onChange} method is 246 * invoked immediately on this thread. 247 * 248 * @param selfChange True if this is a self-change notification. 249 * @param uri The Uri of the changed content. 250 * @param flags Flags indicating details about this change. 251 */ dispatchChange(boolean selfChange, @Nullable Uri uri, @NotifyFlags int flags)252 public final void dispatchChange(boolean selfChange, @Nullable Uri uri, 253 @NotifyFlags int flags) { 254 dispatchChange(selfChange, Arrays.asList(uri), flags); 255 } 256 257 /** 258 * Dispatches a change notification to the observer. Includes the changed 259 * content Uris when available. 260 * <p> 261 * If a {@link Handler} was supplied to the {@link ContentObserver} 262 * constructor, then a call to the {@link #onChange} method is posted to the 263 * handler's message queue. Otherwise, the {@link #onChange} method is 264 * invoked immediately on this thread. 265 * 266 * @param selfChange True if this is a self-change notification. 267 * @param uris The Uri of the changed content. 268 * @param flags Flags indicating details about this change. 269 */ dispatchChange(boolean selfChange, @NonNull Collection<Uri> uris, @NotifyFlags int flags)270 public final void dispatchChange(boolean selfChange, @NonNull Collection<Uri> uris, 271 @NotifyFlags int flags) { 272 dispatchChange(selfChange, uris, flags, UserHandle.getCallingUserId()); 273 } 274 275 /** @hide */ dispatchChange(boolean selfChange, @NonNull Collection<Uri> uris, @NotifyFlags int flags, @UserIdInt int userId)276 public final void dispatchChange(boolean selfChange, @NonNull Collection<Uri> uris, 277 @NotifyFlags int flags, @UserIdInt int userId) { 278 if (mHandler == null) { 279 onChange(selfChange, uris, flags, userId); 280 } else { 281 mHandler.post(() -> { 282 onChange(selfChange, uris, flags, userId); 283 }); 284 } 285 } 286 287 private static final class Transport extends IContentObserver.Stub { 288 private ContentObserver mContentObserver; 289 Transport(ContentObserver contentObserver)290 public Transport(ContentObserver contentObserver) { 291 mContentObserver = contentObserver; 292 } 293 294 @Override onChange(boolean selfChange, Uri uri, int userId)295 public void onChange(boolean selfChange, Uri uri, int userId) { 296 // This is kept intact purely for apps using hidden APIs, to 297 // redirect to the updated implementation 298 onChangeEtc(selfChange, new Uri[] { uri }, 0, userId); 299 } 300 301 @Override onChangeEtc(boolean selfChange, Uri[] uris, int flags, int userId)302 public void onChangeEtc(boolean selfChange, Uri[] uris, int flags, int userId) { 303 ContentObserver contentObserver = mContentObserver; 304 if (contentObserver != null) { 305 contentObserver.dispatchChange(selfChange, Arrays.asList(uris), flags, userId); 306 } 307 } 308 releaseContentObserver()309 public void releaseContentObserver() { 310 mContentObserver = null; 311 } 312 } 313 } 314