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