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